Codeforces 466E Information Graph【Dfs处理父子关系+并查集+离线查询】好题!

来源:互联网 发布:windows平板可以做什么 编辑:程序博客网 时间:2024/04/29 22:25

E. Information Graph
time limit per test
1 second
memory limit per test
512 megabytes
input
standard input
output
standard output

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

  • either employee y became the boss of employeex (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 andm (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 eventt (1 ≤ t ≤ 3).

  • If t = 1, then next follow two integersx and y(1 ≤ x, y ≤ n) — numbers of the company employees. It is guaranteed that employeex 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 integersx 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.

Examples
Input
4 91 4 32 43 3 11 2 32 23 1 21 3 12 23 1 3
Output
YESNOYES

题目大意:

一共有N个点,m个操作。

①1 u,v 表示v是u的父亲节点。

②2 u,表示节点u向父亲传递一个文件,他的父亲会继续向上传递,即节点u的所有父亲节点都会阅读到这个文件(文件编号按照从1到inf的顺序发出)。

③3 u,v表示查询节点u是否阅读过v号文件。


思路:


1、首先我们重点分析查询操作:

①对于查询操作,其实就是在查询发出v号文件的节点x是否是节点u的子节点,如果是,那么就是阅读过,否则就是没有阅读过。那么很显然,我们如果在线连接边的同时,对于每一个查询都O(n)的去Dfs是会超时的。

②既然直接在线搞会超时,那么我们肯定要离线处理这个父子关系问题。首先我们将所有操作都读入,将所有操作1建立有向边:v---->u,同时对于每个点的入度进行统计维护(degree【u】++)。

那么对于所有degree【i】==0的点,都是一棵树的根节点。

③我们设定两个数组,dfn【u】表示Dfs一棵树的过程中,到达点u的时间。left【u】表示Dfs一棵树的过程中,离开点u的时间。

那么如果有两个点:i,x.若其满足:dfn【i】<=dfn【x】<=left【i】,那么节点x就一定是节点i的子节点;

④那么初始预处理时间复杂度O(n),做完的目的就是在查询操作的时候,判断两个点是否是父子节点。


2、那么对于其他操作:

①对于操作1,我们直接将两个点合并到同一个集合中即可(因为查询是需要按照时间顺序来的,所以我们并查集维护两个点是否在同一个集合中来判断两个点是否已经相互连接起来)。

②对于操作2,我们每发出一个编号为x的文件的同时,我们离线处理出所有对编号x文件的查询操作的结果即可,对于两个点u(设定为查询点.是否读过文件x的点),v(发出文件的点),如果节点u和节点v此时处于同一颗树中,并且满足父子关系,那么结果就是YES,否则就是NO。

③对于操作3 ,我们直接跳过即可。


3、最后对结果统一输出即可。


Ac代码:


#include<stdio.h>#include<string.h>#include<vector>using namespace std;struct node{    int op,x,y;}p[100050];int cnt;int f[100050];int num[100050];vector<int >qq[100050];vector<int >mp[100050];int ans[100050];int dfn[100050];int left[100050];int vis[100050];int degree[100050];int find(int a){    int r=a;    while(f[r]!=r)    r=f[r];    int i=a;    int j;    while(i!=r)    {        j=f[i];        f[i]=r;        i=j;    }    return r;}int merge(int a,int b){    int A,B;    A=find(a);    B=find(b);    if(A!=B)    {        f[B]=A;    }}void Dfs(int u){    vis[u]=1;    dfn[u]=++cnt;    for(int i=0;i<mp[u].size();i++)    {        int v=mp[u][i];        if(vis[v]==0)Dfs(v);    }    left[u]=cnt;}int main(){    int n,m;    while(~scanf("%d%d",&n,&m))    {        cnt=0;        int now=1;        memset(ans,-1,sizeof(ans));        memset(degree,0,sizeof(degree));        for(int i=1;i<=n;i++)f[i]=i;        for(int i=1;i<=n;i++)mp[i].clear();        for(int i=0;i<=m;i++)qq[i].clear();        for(int i=0;i<m;i++)        {            scanf("%d",&p[i].op);            if(p[i].op==1)            {                scanf("%d%d",&p[i].x,&p[i].y);                mp[p[i].y].push_back(p[i].x);                degree[p[i].x]++;            }            if(p[i].op==2)            {                scanf("%d",&p[i].x);                p[i].y=now;                now++;            }            if(p[i].op==3)            {                scanf("%d%d",&p[i].x,&p[i].y);                qq[p[i].y].push_back(i);            }        }        for(int i=1;i<=n;i++)        {            if(vis[i]==0&°ree[i]==0)Dfs(i);        }        for(int i=0;i<m;i++)        {            if(p[i].op==3)continue;            if(p[i].op==1)merge(p[i].x,p[i].y);            if(p[i].op==2)            {                int x=p[i].x;                for(int j=0;j<qq[p[i].y].size();j++)                {                    int pos=qq[p[i].y][j];                    int v=p[pos].x;                    if(find(x)==find(v)&&dfn[x]>=dfn[v]&&dfn[x]<=left[v])ans[pos]=1;                    else if(v==x)ans[pos]=1;                    else ans[pos]=0;                }            }        }        for(int i=0;i<m;i++)        {            if(ans[i]==-1)continue;            if(ans[i]==1)printf("YES\n");            else printf("NO\n");        }    }}








0 0