E. Monkeys ###K //K
题目链接:https://codeforces.ml/edu/course/2/lesson/7/1/practice/contest/289390/problem/E
题意:第一只猴子的 尾巴挂在树上 每只猴子的左右手可以抓住其他猴子的尾巴 给定某只猴子
松开某只手的时间 问每只猴子的掉落时间
思路:把删边转换成倒序加边 每次处理两堆集合的时候 如果其中没有根集合(即集合1) 那么就启发式合并
如果有根集合 就更新另一个集合的时间点为i 因为之后就不会再被更新了
1 #include <bits/stdc++.h> 2 #define ll long long 3 #define pb push_back 4 using namespace std; 5 const int maxn=2e5+10; 6 int f[maxn]; 7 int vis[maxn][3]; 8 vector<int>E[maxn]; 9 10 11 int find1(int x) 12 { 13 if(x==f[x]) 14 return x; 15 return f[x]=find1(f[x]); 16 } 17 18 void add(int x,int y) 19 { 20 int t1=find1(x),t2=find1(y); 21 f[t1]=t2; 22 } 23 24 struct ac 25 { 26 int l,r; 27 }; 28 ac a[maxn],c[maxn*2]; 29 int ans[maxn]; 30 31 32 33 int main() 34 { 35 ios::sync_with_stdio(0); 36 cin.tie(0); 37 int n,m; 38 cin>>n>>m; 39 for(int i=1;i<=n;i++) 40 f[i]=i; 41 for(int i=1;i<=n;i++) 42 { 43 cin>>a[i].l>>a[i].r; 44 } 45 for(int i=1;i<=m;i++) 46 { 47 int l,r; 48 cin>>l>>r; 49 c[i].l=l,c[i].r=r; 50 vis[l][r]=1;//l个人的r手 51 } 52 for(int i=1;i<=n;i++) 53 { 54 int l=a[i].l,r=a[i].r; 55 if(l!=-1&&!vis[i][1]) 56 add(i,l); 57 if(r!=-1&&!vis[i][2]) 58 add(i,r); 59 } 60 for(int i=1;i<=n;i++) 61 ans[i]=-1; 62 for(int i=1;i<=n;i++) 63 { 64 E[find1(i)].pb(i); 65 } 66 for(int i=m-1;i>=0;i--) 67 { 68 int p=c[i+1].l,h=c[i+1].r; 69 int t1=find1(p); 70 int t2; 71 if(h==1) 72 t2=find1(a[p].l); 73 else 74 t2=find1(a[p].r); 75 if(t1!=t2) 76 { 77 if(t1==find1(1)) 78 { 79 f[t2]=t1; 80 for(auto &v:E[t2]) 81 ans[v]=i; 82 continue; 83 } 84 if(t2==find1(1)) 85 { 86 f[t1]=t2; 87 for(auto &v:E[t1]) 88 ans[v]=i; 89 continue; 90 } 91 if(E[t1].size()>E[t2].size()) 92 swap(t1,t2); 93 f[t1]=t2; 94 for(auto &v:E[t1]) 95 { 96 E[t2].pb(v); 97 } 98 } 99 } 100 for(int i=1;i<=n;i++) 101 cout<<ans[i]<<'\n'; 102 103 104 105 106 }

浙公网安备 33010602011771号