题目大意:一开始有n个员工,它们互相独立,现有三种操作:
1 x y y称为x的上级
2 x 从x发起一份文件,依次向上级传阅。文件编号依次递增
3 x y 问x是否查阅过编号为y的文件
思路:最暴力的解法就是模拟他的规则,但是这样明显超时。此时,想到了离线操作。我们可以用并查集确定每份文件的发起者和终结者,即文件移动的范围。。然后对于每次询问可以拆成两个标记 ,假设查询x是否浏览过第k号文件,第k号文件的范围为u-v,那么在最后dfs时,遍历到x,判断是否经过u;遍历到v时,判断是否经过x。如果两个都满足,则是YES。(此处参考他人做法)
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <fstream> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <vector> #include <map> #include <set> #include <iomanip> using namespace std; //#pragma comment(linker, "/STACK:102400000,102400000") #define maxn 200005 #define MOD 1000000007 #define mem(a , b) memset(a , b , sizeof(a)) #define LL long long #define ULL unsigned long long typedef pair<int , int> pii; const long long INF=0x3fffffff; int n , m; int fa[maxn] , vis[maxn] , ans[maxn]; vector<int>v[maxn]; vector<pii>q[maxn]; struct node { int st , ed; }rang[maxn] , tmp; int findfa(int a ) { if(fa[a] == a) return a; else return fa[a] = findfa(fa[a] ); } void dfs(int u ) { vis[u] = 1; for (int i = 0; i < v[u].size(); i++) dfs(v[u][i]); for (int i = 0; i < q[u].size(); i++) { int v = q[u][i].first, id = q[u][i].second; if (vis[v]) ans[id]++; } vis[u] = 0; } int main() { while(scanf("%d %d" , &n , &m) != EOF) { mem(ans , 0 ) ; int op , x , y , pos = 1 , K = 1; for(int i = 0 ; i <= n ; i ++) fa[i] = i , v[i].clear(); for(int i = 1 ; i <= m ; i ++) { scanf("%d" , &op); if(op == 1) { scanf("%d %d" , &x , &y); fa[x] = y; v[y].push_back(x); } else if(op == 2) { scanf("%d" , &x); rang[pos].st = x; rang[pos++].ed = findfa(x ); } else { scanf("%d %d" , &x , &y); pii u = make_pair(rang[y].ed , rang[y].st); q[x].push_back(make_pair(u.first, K)); //将K号文件终止节点加入x ,当dfs到x时<span style="font-family: 'Helvetica Neue', Arial, 'Hiragino Sans GB', STHeiti, 'Microsoft YaHei', 'WenQuanYi Micro Hei', SimSun, Song, sans-serif; line-height: 17.230770111084px; white-space: pre-wrap;">,判断是否经过文件的终止点</span> q[u.second].push_back(make_pair(x, K)); // 将查询的x放入K号文件的起点,dfs到K的起点时,判断是否经过x K++; } } for(int i = 1 ; i <= n ;i ++) { if(fa[i] == i) dfs(i); } for(int i = 1 ; i < K ; i ++) { if(ans[i] == 2) printf("YES\n"); else printf("NO\n"); } } return 0; }