并查集是一种用于管理元素所属集合的数据结构,实现为一个森林,其中每棵树表示一个集合,树中的节点表示对应集合中的元素。
并查集支持两种操作:
合并(Union):合并两个元素所属集合(合并对应的树)
查询(Find):查询某个元素所属集合(查询对应的树的根节点),这可以用于判断两个元素是否属于同一集合
(优化)路径压缩
1 2 3 4 5
| int find(int u) { if(f[u]==u) return u; else return f[u]=find(f[u]); }
|
种类并查集
带权并查集
典!
Monkeys
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N =4e5+10;
int a[N][3],ans[N],nxt[N], p[N],w[N],vis[N][3],fa[N],head[N],tail[N];
int find(int x) { if(fa[x]==x) return x; return fa[x]=find(fa[x]); }
void merge(int u,int v,int p) { int fu=find(u); int fv=find(v); if(fu==fv) return; if(fu>fv) swap(fu,fv); if(fu==1 && p!=-1) { for(int use=head[fv];use;use=nxt[use]) ans[use]=p; } fa[fv]=fu; nxt[tail[fu]]=head[fv]; tail[fu]=tail[fv]; }
int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n,m; cin>>n>>m; for(int i=1;i<=n;i++) { cin>>a[i][1]>>a[i][2]; ans[i]=-1; } for(int i=0;i<m;i++) { cin>>p[i]>>w[i]; vis[p[i]][w[i]]=1; } for(int i=1;i<=n;i++) { fa[i]=head[i]=tail[i]=i; nxt[i]=0; } for(int i=1;i<=n;i++) { if(!vis[i][1] && a[i][1]!=-1) merge(i,a[i][1],-1); if(!vis[i][2] && a[i][2]!=-1) merge(i,a[i][2],-1); } for(int i=m-1;i>=0;i--) { int u=p[i],v=a[p[i]][w[i]]; merge(u,v,i); } for(int i=1;i<=n;i++) { cout<<ans[i]<<endl; } return 0; }
|