题意
有 n 个雇员在公司 “X” 工作 (为方便考虑,将他们从 1 到 n 编号)。最初,雇员之间没有任何关系。在接下来的每 m 天中,每天发生以下事件中的一件:
要么雇员 y 变成雇员 x 的上司 (那时,雇员 x 尚未拥有一个上司);
要么雇员 x 取得一小包文件并签署它们,然后他将这一小包给了他的上司。他的上司签署了这些文件,并将它们给了更上一层的上司,依此类推 (签署文件的最后一人,将它们发送到归纳箱中);
要么类型为 “判断雇员 x 是否签署了特定的文件” 的一个请求到来。
您的任务是编写一个程序,给定这些事件的情况下,回答所描述类型的查询。在那时,数据保证:在整个工作时间,公司中没有循环依赖。
分析
这道题我们可以采用离线处理
首先我我们先去建图,在建图的过程中如果遇到了文件传输的话,我们记录每一个文件的起点和终点,起点比较好确定,就是我输入的数值,那么怎么去确认终点呢?我们可以去维护一个并查集
然后我们去处理每一个询问,其实就是去判断询问的点是不是在对应的那条路径上面,我们已经有了起点,终点,待判断的点,可以用最近公公祖先去处理这个问题,待判断的点和起点的LCA为他本身,待判断的点和终点的LCA为终点,同时记得判断一下三点个是否在同一个联通快内部即可
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstring>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC option("arch=native","tune=native","no-zero-upper")
#pragma GCC target("avx2")
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
int h[N],ne[N],e[N],idx;
int f[N][21];
int res;
int line1[N],line2[N];
int q[N];
int d[N];
int ppp[N];
int qid[N];
int n,m,num;
void add(int a,int b){
ne[idx] = h[a],e[idx] = b,h[a] = idx++;
}
int find(int x){
if(x != q[x]) q[x] = find(q[x]);
return q[x];
}
void bfs(int root){
d[0] = 0,d[root] = 1;
queue<int> Q;
Q.push(root);
while(Q.size()){
int t = Q.front();
Q.pop();
for(int i = h[t];~i;i = ne[i]){
int j = e[i];
if(d[j] > d[t] + 1){
d[j] = d[t] + 1;
Q.push(j);
f[j][0] = t;
for(int k = 1;k <= 20;k++)
f[j][k] = f[f[j][k - 1]][k - 1];
}
}
}
}
int LCA(int a,int b){
if(d[a] < d[b]) swap(a,b);
for(int i = 20;i >= 0;i--)
if(d[f[a][i]] >= d[b])
a = f[a][i];
if(a == b) return a;
for(int i = 20;i >= 0;i--)
if(f[a][i] != f[b][i])
a = f[a][i],b = f[b][i];
return f[a][0];
}
int main(){
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
for(int i = 1;i <= n;i++) q[i] = i;
while(m--){
int op,x,y;
scanf("%d",&op);
if(op == 1){
scanf("%d%d",&x,&y);
add(y,x);
q[x] = find(y);
}
else if(op == 2){
scanf("%d",&x);
line1[++res] = x;
line2[res] = find(x);
}
else{
scanf("%d%d",&x,&y);
ppp[++num] = x;
qid[num] = y;
}
}
memset(d,0x3f,sizeof d);
for(int i = 1;i <= n;i++)
if(q[i] == i)
bfs(i);
for(int i = 1;i <= num;i++){
int id = qid[i],x = ppp[i];
int st = line1[id],ed = line2[id];
int a = find(st),b = find(ed),c = find(x);
if(a != b || b != c || a != c){
puts("NO");
continue;
}
if(LCA(st,x) == x && LCA(x,ed) == ed)
puts("YES");
else
puts("NO");
}
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/