/*
*Rainto96
*Beijing University of Posts and Telecommunications School of Software Engineering
*http://blog.youkuaiyun.com/u011775691
题意:
给出10万个点,10万个操作
操作有三种
1.x->y 指定x为y的上级
2.给x一份文件,x签名后给上级,上级签名后给上级的上级,直到没有上级
3.询问x是否签名了文件id
id按输入顺序加一,初始为1
解法:
搞
操作1就是并查集合并,然后x就是y的父亲
操作2就记录下来两个端点,一个是x,一个是当时的并查集树根
操作3就输入完所有输入建完树后,查询x是否在id文件的两个端点fa,son之间,很好判断
做一个虚拟根(可能是森林) ,然后dfs出LCA,如果x是在两个端点fa,son之间的路径上,则肯定有lca(x,fa) = fa , lca(x, son ) = x 即可
*/
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define ALL(x) x.begin(),x.end()
#define VINT vector<int>
#define PII pair<int,int>
#define MP(x,y) make_pair((x),(y))
#define ll long long
#define ull unsigned ll
#define MEM0(x) memset(x,0,sizeof(x))
#define MEM(x,val) memset((x),val,sizeof(x))
#define scan(x) scanf("%d",&(x))
#define scan2(x,y) scanf("%d%d",&(x),&(y))
#define scan3(x,y,z) scanf("%d%d%d",&(x),&(y),&(z))
#define scan4(x,y,z,k) scanf("%d%d%d%d",&(x),&(y),&(z),&(k))
#define Max(a,b) a=max(a,b)
#define Min(a,b) a=min(a,b)
using namespace std;
const int MAXN= 111111;
int par[MAXN];
VINT G[MAXN];
int f[MAXN];
int find(int u){
return par[u]==u?u:par[u]=find(par[u]);
}
void unit(int u,int v){//u is v's boss
u= find(u) , v= find(v);
if(u==v) return;
par[v] = u;
}
int fa[33][MAXN] , depth[MAXN] , vis[MAXN];
void fafs(int now, int fat ,int dep){
fa[0][now] = fat;
depth[now] = dep;
vis[now] =true;
for(auto to:G[now]){
if(vis[to]) continue;
fafs(to, now ,dep+1);
}
}
int LOG_N=20;
//计算u和v的LCA
int lca(int u,int v) {
if(depth[u]>depth[v]) swap(u,v);
for(int k=0;k<LOG_N;k++) if((depth[v]-depth[u])>>k&1) v=fa[k][v];
if(u==v) return u;
for(int k=LOG_N-1;k>=0;k--)if(fa[k][u]!=fa[k][v]) u=fa[k][u] , v=fa[k][v];
return fa[0][u];
}
PII v[MAXN];
int main(){
#ifndef ONLINE_JUDGE
//freopen("C:/OJ/in.txt","r",stdin);
#endif
int n ,m;
scan2(n,m);
for(int i=1;i<=n;i++) par[i]= i;
int doc = 1;
vector<PII > que;
for(int i=1;i<=m;i++){
int t;scan(t);
if(t==1){
int x,y;scan2(x,y);
unit(y,x);
G[y].pb(x);
}else if(t==2){
int x; scan(x);
int fa = find(x);
//v.pb(MP(fa,MP(x,doc++)));
v[doc++]=MP(fa,x);
}else{
int x,id;scan2(x,id);
que.pb(MP(x,id));
}
}
int root=0;
for(int i=1;i<=n;i++){
G[root].pb(find(i));
}
fafs(root ,-1 ,0);
for(int k=0;k+1<LOG_N;k++)for(int v=1;v<=n;v++)
if(fa[k][v]<0) fa[k+1][v]=-1;
else fa[k+1][v]=fa[k][fa[k][v]];
for(int i=0;i<que.size();i++){
int x = que[i].first , id= que[i].second;
int fat = v[id].first , son = v[id].second;
if(lca(fat,x)==fat && lca(x,son)==x){
puts("YES");
}else puts("NO");
}
return 0;
}
Codeforces 466E LCA+搞
最新推荐文章于 2024-08-31 10:23:18 发布