并查集启发式合并

并查集启发式合并

挺好想的,最简单的方法是并查集启发式合并,加暴力跳父亲。

然而,这个代码量比较小,比较好写,所以我写了 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;
}

  

05-11 13:42