[bzoj3282]Tree_LCT

Tree bzoj-3282

题目大意:给你n个点,m个操作,支持:非联通两点加边,直接连通两点间删边,更改单点权值,查询路径点权异或和。

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

想法:这...果真是,LCT的题都是裸题。我们直接维护一个大的LCT,加边用link,删边用cut,干着两个事之前需要find判断一下这两个点的连通性。之后的异或和,我们只需要维护子树异或和。这样我们每次将左端点make_root,然后对于右端点access,之后我们需要询问的区间就是一棵子树,直接查询即可。

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

#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好强...

猜你喜欢

转载自www.cnblogs.com/ShuraK/p/9280305.html