Information Graph CodeForces - 466E

There are n employees working in company “X” (let’s number them from 1 to n for convenience). Initially the employees didn’t have any relationships among each other. On each of m next days one of the following events took place:

either employee y became the boss of employee x (at that, employee x didn’t have a boss before);
or employee x gets a packet of documents and signs them; then he gives the packet to his boss. The boss signs the documents and gives them to his boss and so on (the last person to sign the documents sends them to the archive);
or comes a request of type “determine whether employee x signs certain documents”.
Your task is to write a program that will, given the events, answer the queries of the described type. At that, it is guaranteed that throughout the whole working time the company didn’t have cyclic dependencies.

Input
The first line contains two integers n and m (1 ≤ n, m ≤ 105) — the number of employees and the number of events.

Each of the next m lines contains the description of one event (the events are given in the chronological order). The first number of the line determines the type of event t (1 ≤ t ≤ 3).

If t = 1, then next follow two integers x and y (1 ≤ x, y ≤ n) — numbers of the company employees. It is guaranteed that employee x doesn’t have the boss currently.
If t = 2, then next follow integer x (1 ≤ x ≤ n) — the number of the employee who got a document packet.
If t = 3, then next follow two integers x and i (1 ≤ x ≤ n; 1 ≤ i ≤ [number of packets that have already been given]) — the employee and the number of the document packet for which you need to find out information. The document packets are numbered started from 1 in the chronological order.
It is guaranteed that the input has at least one query of the third type.

Output
For each query of the third type print “YES” if the employee signed the document package and “NO” otherwise. Print all the words without the quotes.

Example
Input
4 9
1 4 3
2 4
3 3 1
1 2 3
2 2
3 1 2
1 3 1
2 2
3 1 3
Output
YES
NO
YES

/*``
題意:好複雜2333嗯。。自己看看吧大概也看得懂。。。2333(其實是我忘記了=-=)
思路:對同一個文件的查詢,查詢的關係樹應該是2操作時的關係樹,所以對每個2操作 我們可以把所有的對當時文件的查詢一起處理。這裏學到了個很厲害的東西。用dfs標記一個點入棧退棧的時間,用一個時間戳Index來計算,那麼如果有一對點u,v,v在u到根節點的路徑上,即r->v->u;那麼必定存在 l[v]<l[u] r[v]>r[u]。由於1操作對關係圖中的時間戳不會產生影響,並且需要將對同一文件的查詢一起處理,所以我們先把所有操作讀入,然後一起操作。2333
對每個1操作,我們用並查集合並x,y,然後先將所有3操作根據文件標號存好,對每個2操作去查詢得到當前文件的人和被查詢的人是不是同屬一個集合,如果屬於一個集合說明已經被合併如果同時滿足lr的關係那麼說明yes 不然no2333
*/

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
#include<stack>
#include<map>
using namespace std;

//thanks to pyf ...

#define INF 0x3f3f3f3f
#define CLR(x,y) memset(x,y,sizeof(x))
#define mp(x,y) make_pair(x,y)
typedef pair<int,int> PII;
typedef long long ll;

const int N = 1e5+5;

int fa[N];
vector<int>G[N];//存圖
vector<PII>Q[N];//用來存放查詢 first是查詢的人 second是查詢的編號
int l[N],r[N];//入退棧的時間
int ok[N];//yes or no
int vis[N];//用來標記是否有入度,沒入度的是根節點
int Index = 0;//時間戳
int doc_id = 0;//文件標號
int n,m;
struct Q
{
    int op;
    int x,y;
}query[N];
void init()//初始化函數
{
    CLR(ok,0);
    CLR(vis,0);
    CLR(l,0);
    CLR(r,0);
    Index = 0;
    doc_id = 0;
    for(int i=0;i<=N;i++)
    {
        fa[i] = i;
        G[i].clear();
        Q[i].clear();
    }

}
int find(int x)
{
    if(fa[x]!=x)
        fa[x] = find(fa[x]);
    return fa[x];
}
void merge(int a,int b)
{
    a = find(a);
    b = find(b);
    if(a!=b)
        fa[a] = fa[b];
}
void get_query()//預處理所有操作
{
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
        int op;
        scanf("%d",&query[i].op);
        if(query[i].op==1)
        //反向建圖,這樣由最高領導指向所有下屬,在dfs時對根節點不會重複的去覆蓋lr值
        {
            scanf("%d%d",&query[i].x,&query[i].y);
            G[query[i].y].push_back(query[i].x);
            vis[query[i].x] = 1; // 有入度 不是根節點
        }
        else if(query[i].op == 2)
        {
            scanf("%d",&query[i].x);
            query[i].y = ++ doc_id;
        }
        else
        {
            scanf("%d%d",&query[i].x,&query[i].y);
            Q[query[i].y].push_back(mp(query[i].x,i));
            //對同一個文件的查詢存放在一起
        }
    }
}
void dfs(int u)//處理 lr
{
    vis[u] = 1;
    l[u] = ++ Index;
    for(int i=0;i<G[u].size();i++)
    {
        int v = G[u][i];
        dfs(v);
    }
    r[u] = ++Index;
}
int main()
{
    while(scanf("%d",&n)==1)
    {
        init();
        get_query();
        for(int i=1;i<=n;i++)
            if(!vis[i])
                dfs(i);
        for(int i=0;i<m;i++)
        {
            if(query[i].op == 1)
            {
                merge(query[i].x,query[i].y);
            }
            else if(query[i].op==2)
            {
                int get_p = query[i].x;
                int doc = query[i].y;
                for(int j=0;j<Q[doc].size();j++)
                //判斷是否可行
                {
                    int p = Q[doc][j].first;
                    int id = Q[doc][j].second;
//                  cout << get_p << " " << p << " ";
//                  cout << l[get_p] << " " << l[p] << " " << r[get_p] << " " << r[p] << " " << find(get_p) << " " << find(p) << endl;
                    if(l[get_p]>=l[p]&&r[get_p]<=r[p]&&(find(get_p)==find(p)))
                        ok[id] = 1;
                }
            }
        }
        for(int i=0;i<m;i++)
            if(query[i].op == 3)
                ok[i]==1 ? cout << "YES" << endl : cout << "NO" << endl;
    }
    return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章