版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jerry99s/article/details/84653533
题目: http://codeforces.com/problemset/problem/466/E
题意:
三种操作:
1.y变为x的boss;
2.x签署一份文件并逐级往上传并签署;
3.查询第x个人是否签署第i份文件。
分析:
在线变离线;
用路径压缩的并查集能直接查询当前状态下某个人的最高boss;
签署一份文件时,记录签署此文件最底端的人和最顶端的人;
倍增处理出每个节点往上走1<<i步是谁;
处理出每个节点的深度deep[i]。
对于每个查询:
从第i个文件的最底端往上走(deep[x]-deep[i文件底端])步;
并查询走到的这个节点是否为x。
代码:
//jerry99
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int tmax=1e5+5;
int n,m,fa[tmax][20],f[tmax],deep[tmax];
int Start[tmax],End[tmax],num,numq;
struct node{
int people,packnum;
};
node q[tmax];
vector<int> G[tmax];
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
void dfs(int x,int d)
{
deep[x]=d;
int i,len=G[x].size();
for(i=0;i<len;i++)
dfs(G[x][i],d+1);
return;
}
void init()
{
int i,j;
for(j=1;j<=17;j++)
for(i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for(i=1;i<=n;i++)
if(find(i)==i)
dfs(i,1);
return;
}
void work()
{
int i,j,Dif,s,t,check;
for(j=1;j<=numq;j++)
{
s=Start[q[j].packnum];
t=End[q[j].packnum];
check=q[j].people;
//printf("s=%d t=%d\n",s,t);
if(find(s)!=find(check)||deep[s]<deep[check]||deep[check]<deep[t])
{
printf("NO\n");
continue;
}
Dif=deep[s]-deep[check];
for(i=17;i>=0;i--)
{
if(Dif<(1<<i)) continue;
Dif-=(1<<i);
s=fa[s][i];
if(s==0) break;
}
if(s!=check) printf("NO\n");
else printf("YES\n");
}
return;
}
int main()
{
scanf("%d%d",&n,&m);
int i,t,x,y;
for(i=1;i<=n;i++)
f[i]=i;
for(i=1;i<=m;i++)
{
scanf("%d",&t);
if(t==1)
{
scanf("%d%d",&x,&y);
fa[x][0]=y;
G[y].push_back(x);
f[x]=find(y);
}
else if(t==2)
{
num++;
scanf("%d",&Start[num]);
End[num]=find(Start[num]);
}
else
{
numq++;
scanf("%d%d",&q[numq].people,&q[numq].packnum);
}
}
init();
work();
return 0;
}