Codeforces-Gadget Hackwrench-LCA最近公共祖先

題目鏈接:http://codeforces.com/gym/100685/problem/G


Gadget Hackwrench
time limit per test
2 seconds
memory limit per test
64 megabytes
input
standard input
output
standard output

Chip 'n' Dale rescue rangers! But observant viewers know that help is usually required by Chip and Dale themselves. Today you are in the role of cunning Gadget Hackwrench.

So, Chip and Dale are again in the paws of Fat Cat. He doesn't like rodents much and therefore prepared a treacherous test. He is going to put them to a labyrinth and see if they can escape from it. The labyrinth is actually built as a tree where each edge has fixed direction (by definition tree is a connected unoriented graph without cycles).

Gadget has intercepted a talk between Fat Cat and his henchmen about future tests. For each test round she knows the exact location where Chip and Dale are to be put by Fat Cat and the location of an exit. Gadget wants to compute whether they will be able to find an exit for each test.

Input

The first line of input contains an integer N (1 ≤ N ≤ 105) — the number of vertices in a graph.

On the next N - 1 lines of input directed arcs of the tree are given. On the (i + 1)th line integer numbers ai and bi are given (1 ≤ ai, bi ≤ N) denoting an arc from vertex ai to vertex bi. It is guaranteed that arcs a1, a2, ..., an - 1 without orientation form a tree.

Then a string with integer number M (1 ≤ M ≤ 105) is given — the number of queries to process. Next M lines describe queries:(n + 1 + i)th line contain integers xi and yi (1 ≤ xi, yi ≤ N).

Output

For each query please output a separate line containing 'Yes' (without quotes) if graph contains a path between xi and yi, or 'No' (without quotes) in other case.

Examples
input
4
1 2
3 1
4 1
6
1 2
3 2
2 3
4 2
4 3
2 1
output
Yes
Yes
No
Yes
No
No


一道LCA的題,記錄每個節點到根節點需要經過幾個方向向下的邊(用flag數組來存)。然後最後判斷是否合法只需要判斷,這兩個點到他們的最近公共祖先是否合法。比如LCA(a,b)爲a,b的最近公共祖先,這兩個點分別爲a,b;那麼就是判斷flag[a]-flag[LCA(a,b)]是否等於0以及flag[b]-flag[LCA(A,B)]是否等於他們的深度差。LCA(a,b)爲a,b的最近公共祖先。

代碼如下。

//RMQst表來做LCA
//樹的節點是從1到n開始排列。
//fat[i][j]表示第i個節點的第2^j個祖先是誰
//2^20 = 1 048 576
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define maxn 100010
using namespace std;
int flag[maxn];

int fat[maxn][30];
int len[maxn];
int n;
struct node{
    int val,dir;
};
vector<node>v[maxn];
void dfs(int now,int father)
{
    fat[now][0]=father;
    len[now]=len[father]+1;
    for(int i=0;i<v[now].size();i++)
    {
        if(v[now][i].val==father)
            continue;
        if(v[now][i].dir)
        flag[v[now][i].val]=flag[now]+1;
        else flag[v[now][i].val]=flag[now];
        dfs(v[now][i].val,now);

    }

}
void init()
{

    memset(len,0,sizeof(len));
    memset(fat,0,sizeof(fat));
    memset(flag,0,sizeof(flag));

    int i,j;
    dfs(1,0);
    for(int i=1;i<=19;i++)
    {
        for(int j=1;j<=n;j++)
        {
            fat[j][i]=fat[fat[j][i-1]][i-1];

        }

    }
}
int lca(int x,int y)
{
    if(len[x]>len[y])
        swap(x,y);
    //保證x的深度較小
    //下面只需要將y拉到x的位置就好
    for(int i=19;i>=0;i--)
    {
       if(len[fat[y][i]]>=len[x])
        y=fat[y][i];

    }
    //現在x,y已經在同一高度
    //可以求LCA了
      if(x==y)
    {
        return x;//這是x和y其中一個是另一個的祖宗
    }
    for(int i=19;i>=0;i--)
    {
        if(fat[y][i]!=fat[x][i])
        {
            y=fat[y][i];
            x=fat[x][i];

        }

    }

    return fat[x][0];
}

int main()
{
    int uu,vv;
    int m;

    while(scanf("%d",&n)!=EOF)
    {
    for(int i=0;i<maxn;i++)
    {
        v[i].clear();
    }
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&uu,&vv);
            node vvv,uuu;
            vvv.val=vv;
            uuu.val=uu;
            uuu.dir=1;
            vvv.dir=0;
            v[uu].push_back(vvv);
            v[vv].push_back(uuu);
        }
        init();
     scanf("%d",&m);
     for(int i=1;i<=m;i++)
     {
         flag[0]=0;
         scanf("%d%d",&uu,&vv);
         int root=lca(uu,vv);
         int fuck,cao;
         fuck=flag[uu]-flag[root];
         cao=flag[vv]-flag[root];
         if(cao==0&&fuck==len[uu]-len[root])
            flag[0]=1;

         if(flag[0])
            printf("Yes\n");
         else printf("No\n");


     }
    }

}







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章