BZOJ 4668: 冷战 并查集启发式合并/LCT
挺好想的,最简单的方法是并查集启发式合并,加暴力跳父亲。
然而,这个代码量比较小,比较好写,所以我写了 LCT,更具挑战性。
#include <cstdio> #include <algorithm> #define N 1000004 #define lson t[x].ch[0] #define rson t[x].ch[1] #define setIO(s) freopen(s".in","r",stdin) using namespace std; int sta[N],n,m,p[N]; struct Node { int ch[2],max,val,rev,f; }t[N]; int find(int x) { return p[x]==x?x:p[x]=find(p[x]); } int get(int x) { return t[t[x].f].ch[1]==x; } int isrt(int x) { return !(t[t[x].f].ch[0]==x||t[t[x].f].ch[1]==x); } void pushup(int x) { t[x].max=t[x].val; t[x].max=max(max(t[lson].max,t[rson].max), t[x].max); } void mark(int x) { if(!x) return; swap(lson, rson), t[x].rev^=1; } void pushdown(int x) { if(t[x].rev) mark(lson), mark(rson), t[x].rev=0; } void rotate(int x) { int old=t[x].f,fold=t[old].f,which=get(x); if(!isrt(old)) t[fold].ch[t[fold].ch[1]==old]=x; t[old].ch[which]=t[x].ch[which^1], t[t[old].ch[which]].f=old; t[x].ch[which^1]=old,t[old].f=x,t[x].f=fold; pushup(old),pushup(x); } void splay(int x) { int v=0,u=x,fa; for(sta[++v]=u;!isrt(u);u=t[u].f) sta[++v]=t[u].f; for(int i=v;i>=1;--i) pushdown(sta[i]); for(u=t[u].f;(fa=t[x].f)!=u;rotate(x)) if(t[fa].f!=u) rotate(get(fa)==get(x)?fa:x); } void Access(int x) { for(int y=0;x;y=x,x=t[x].f) { splay(x),rson=y,pushup(x); } } void makeroot(int x) { Access(x),splay(x),mark(x); } void split(int x,int y) { makeroot(x),Access(y),splay(y); } void link(int x,int y) { makeroot(x), makeroot(y),t[x].f=y; } int main() { int i,j,cc=0; scanf("%d%d",&n,&m); for(i=1;i<=n;++i) p[i]=i; int lastans=0,tot=n; for(i=1;i<=m;++i) { int op,x,y; scanf("%d%d%d",&op,&x,&y); x^=lastans,y^=lastans; if(op==0) { ++cc; x=find(x),y=find(y); if(x!=y) { ++tot; p[x]=p[y]=p[tot]=tot; t[tot].val=cc; link(x,tot),link(tot,y); } } else { int xx=find(x),yy=find(y); if(xx!=yy) printf("0\n"),lastans=0; else { split(x,y); printf("%d\n",lastans=t[y].max); } } } return 0; }