Tree bzoj-3282

题目大意:给你n个点m个操作。更改单点权值,加边,删边;查询路径异或和。

注释:$1\le n,m\le 10^5$

想法:看到了加边删边,果断想到LCT维护。至于路径异或和,我们只需要维护每个点对应splay的子树异或和,然后查询的时候直接access+splay,makeroot之后就行了。

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 300050
#define ls ch[p][0]
#define rs ch[p][1]
#define get(x) (ch[f[x]][1]==x)
int ch[N][2],f[N],sum[N],n,m,val[N],rev[N];
inline bool isrt(int p)
{
    return ch[f[p]][1]!=p&&ch[f[p]][0]!=p;
}
inline void pushdown(int p)
{
    if(rev[p])
	{
        swap(ch[ls][0],ch[ls][1]);
        swap(ch[rs][0],ch[rs][1]);
        rev[ls]^=1; rev[rs]^=1;
        rev[p]=0;
    }
}
inline void pushup(int p)
{
    sum[p]=sum[ls]^sum[rs]^val[p];
}
inline void update(int p)
{
    if(!isrt(p)) update(f[p]);
    pushdown(p);
}
void rotate(int x)
{
    int y=f[x],z=f[y],k=get(x);
    if(!isrt(y)) ch[z][ch[z][1]==y]=x;
    ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
    ch[x][!k]=y; f[y]=x; f[x]=z;
    pushup(y); pushup(x);
}
void splay(int x)
{
    update(x);
    for(int fa;fa=f[x],!isrt(x);rotate(x))
        if(!isrt(fa))
            rotate(get(fa)==get(x)?fa:x);
}
void access(int p)
{
    int t=0;
    while(p) splay(p),rs=t,pushup(p),t=p,p=f[p];
}
void makeroot(int p)
{
    access(p); splay(p);
    swap(ls,rs); rev[p]^=1;
}
void link(int x,int p)
{
    makeroot(x); f[x]=p;
}
void cut(int x,int p)
{
    makeroot(x); access(p); splay(p); ls=f[x]=0;
}
int find(int p)
{
    access(p); splay(p);
    while(ls) pushdown(p),p=ls;
    return p;
}
void fix(int x,int v)
{
    splay(x);
	sum[x]^=val[x];
	val[x]=v;
	sum[x]^=val[x];
}
int main()
{
    scanf("%d%d",&n,&m);
    int i,x,y,opt;
    for(i=1;i<=n;i++) scanf("%d",&val[i]);
    for(i=1;i<=m;i++)
	{
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==0)
		{
            makeroot(x); access(y); splay(y);
            printf("%d\n",sum[y]);
        }else if(opt==1)
		{
            int t1=find(x),t2=find(y);
            if(t1!=t2) link(x,y);
        }else if(opt==2)
		{
            int t1=find(x),t2=find(y);
            if(t1==t2) cut(x,y);
        }else
		{
            fix(x,y);
        }
    }
}

小结:LCT的题有很明显的特点,就是动态维护加边删边,一般要是你能做上就上LCT吧,别的能维护动态树我也不会啊...