BZOJ 4668: 冷战
Description
在一个图上,在两个点间连一条边,问这两个点最早在什么时候联通.
Sol
并查集+启发式合并.
按秩合并的并查集...我也不知道什么是按秩合并,反正就跟启发式合并差不多,合并的时候将小的往大的里和,因为每次增长都是小集合倍数的两倍以上,所以层数不超过 \(log n\)
然后连边的时候记录一下是第几次连接的,统计一下深度,最后暴力找LCA...
Code
/************************************************************** Problem: 4668 User: BeiYu Language: C++ Result: Accepted Time:1256 ms Memory:9104 kb ****************************************************************/ #include <bits/stdc++.h> using namespace std; const int N = 5e5+50; int n,lst; struct UnionTable { int f[N],s[N],v[N],d[N]; void init(int n) { for(int i=1;i<=n;i++) f[i]=i,v[i]=0,s[i]=1; } int find(int x) { if(f[x]^x) { int fa=find(f[x]); d[x]=d[f[x]]+1; return fa; }else return x; } void Union(int x,int y,int c) { int f1=find(x),f2=find(y); if(f1==f2) return; if(s[f1]>s[f2]) f[f2]=f1,v[f2]=c,s[f1]+=s[f2]; else f[f1]=f2,v[f1]=c,s[f2]+=s[f1]; } int Query(int x,int y) { int f1=find(x),f2=find(y),r=0; if(f1!=f2) return 0; for(;x^y;) { if(d[x]<d[y]) swap(x,y); r=max(r,v[x]),x=f[x]; }return r; } }un; inline int in(int x=0,char ch=getchar()) { while(ch>'9' || ch<'0') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; } int main() { n=in(); un.init(n); for(int m=in(),c=0;m--;) { int opt=in(),u=in()^lst,v=in()^lst; if(!opt) un.Union(u,v,++c); else printf("%d\n",lst=un.Query(u,v)); }return 0; }