写下之前自己被困住的几个点吧:
1.access找的不是到真实的根的一条路径,而是到能找到的最上面的splay的根(makeroot同理)
2.findroot找的是x所在原树的树根(深度最小),并旋转至当前一棵splay的根
tips:具体的还是没特别懂,多做题吧
#include<cstdio> #include<cctype> #include<algorithm> #define ls tr[x][0] #define rs tr[x][1] #define maxn 300002 using namespace std; int n,m,res[maxn],tr[maxn][2],rev[maxn],w[maxn],tmp[maxn],f[maxn]; inline void pushup(int x){res[x]=res[ls]^res[rs]^w[x];} inline void pushr(int x){swap(ls,rs);rev[x]^=1;} inline void pushdown(int x){if(rev[x]){if(ls)pushr(ls);if(rs)pushr(rs);rev[x]=0;}} inline void read(int &x){ char ch=getchar();x=0;int f=1; while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} x*=f; } inline bool isroot(int x){return (tr[f[x]][0]==x||tr[f[x]][1]==x);} inline void rotate(int x){ int fa=f[x],gfa=f[fa],whicx=tr[fa][1]==x,flag=isroot(fa);//注意flag要先赋值,因为若之后其父亲会变为x tr[fa][whicx]=tr[x][whicx^1];if(tr[fa][whicx])f[tr[fa][whicx]]=fa; tr[x][whicx^1]=fa;f[fa]=x; f[x]=gfa; if(flag)tr[gfa][tr[gfa][1]==fa]=x; pushup(fa); } inline void splay(int x){ int y=x,siz=0,z; tmp[++siz]=y; while(isroot(y))tmp[++siz]=y=f[y]; while(siz)pushdown(tmp[siz--]); while(isroot(x)){ y=f[x];z=f[y]; if(isroot(y))rotate((tr[y][1]==x)==(tr[z][1]==y)?y:x); rotate(x); } pushup(x); } inline void access(int x){ for(int y=0;x;x=f[y=x])splay(x),rs=y,pushup(x); } inline void makeroot(int x){access(x);splay(x);pushr(x);} inline void split(int x,int y){makeroot(x);access(y);splay(y);} inline int findroot(int x){ access(x);splay(x); while(ls)pushdown(x),x=ls; return x; } inline void link(int x,int y){makeroot(x);if(findroot(y)!=x)f[x]=y;} inline void cut(int x,int y){ makeroot(x);if(findroot(y)==x&&f[x]==y&&!rs){f[x]=tr[y][0]=0;pushup(y);} } int main(){ read(n);read(m); int typ,x,y; for(int i=1;i<=n;i++)read(w[i]); while(m--){ read(typ);read(x);read(y); switch(typ){ case 0:split(x,y);printf("%d ",res[y]);break; case 1:link(x,y);break; case 2:cut(x,y);break; case 3:makeroot(x);w[x]=y;pushup(x); } } }