并查集+启发式合并+LCA思想 || 冷战 || BZOJ 4668
题面:bzoj炸了,以后再补发
题解:
并查集,然后对于每个点记录它与父亲节点联通的时刻 tim ,答案显然是 u 到 v 的路径上最大的 tim 值。启发式合并,把 size 小的子树往大的上并,可以证明树高是 log N 的(我不会),
所以最后套一个LCA思想,直接向上跳着找出路径上最大的 tim 值即为答案,时间复杂度O(N log N)。
代码:
1 #include<cstdio> 2 #include<iostream> 3 #define max(a,b) ((a)>(b)?(a):(b)) 4 using namespace std; 5 inline int rd(){ 6 int x=0;char c=getchar(); 7 while(c<'0'||c>'9')c=getchar(); 8 while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} 9 return x; 10 } 11 const int maxn=5e5+5,maxm=5e5+5; 12 int N,M,o,u,v,ans=0,fa[maxn],tim[maxn],now=0,f1,f2,siz[maxn]; 13 int now_tim=0; 14 inline int getf(int n){ 15 if(fa[n]==n) return n; 16 return getf(fa[n]); 17 } 18 inline int getdep(int n){ 19 int cnt=0; 20 while(fa[n]!=n){ 21 cnt++; 22 n=fa[n]; 23 } 24 return cnt; 25 } 26 int main(){ 27 N=rd(); M=rd(); 28 for(int i=1;i<=N;i++) fa[i]=i,siz[i]=1; 29 while(M--){ 30 o=rd(); u=rd(); v=rd(); 31 u=u^ans; v=v^ans; 32 if(o==0){ 33 now_tim++; 34 f1=getf(u); f2=getf(v); 35 if(f1!=f2){ 36 if(siz[f1]>siz[f2]) swap(f1,f2); 37 siz[f2]+=siz[f1]; 38 fa[f1]=f2; 39 tim[f1]=now_tim; 40 } 41 } 42 else{ 43 f1=getf(u); f2=getf(v); 44 ans=0; 45 if(f1!=f2) { 46 printf("%d\n",ans); 47 continue; 48 } 49 int dep1=getdep(u),dep2=getdep(v); 50 if(dep1<dep2) swap(dep1,dep2),swap(u,v); 51 while(dep1>dep2){ 52 dep1--; 53 ans=max(ans,tim[u]); 54 u=fa[u]; 55 } 56 if(u!=v){ 57 while(fa[u]!=fa[v]){ 58 ans=max(ans,tim[u]); 59 ans=max(ans,tim[v]); 60 u=fa[u]; v=fa[v]; 61 } 62 ans=max(ans,tim[u]); 63 ans=max(ans,tim[v]); 64 } 65 printf("%d\n",ans); 66 } 67 } 68 return 0; 69 }
By:AlenaNuna