您的位置:首页 > 其它

Information Graph CodeForces - 466E

2017-05-08 10:13 211 查看
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
;
vector<int>G
;//存图
vector<PII>Q
;//用来存放查询 first是查询的人 second是查询的编号
int l
,r
;//入退栈的时间
int ok
;//yes or no
int vis
;//用来标记是否有入度,没入度的是根节点
int Index = 0;//时间戳
int doc_id = 0;//文件标号
int n,m;
struct Q
{
int op;
int x,y;
}query
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: