题目:
题解:
这就是LCT的裸题啦,单点修改啦,区间查询xor啦,都是比较简单的操作
单点修改直接修改就好啦,然后access一下,从下面到上面的access最适合我们update值了,那就在access里面update几次?
区间查询在update里面搞点事情就行
后面有小总结啦
代码:
#include <cstdio>
#include <iostream>
using namespace std;
const int N=300005;
int ch[N][2],xo[N],delta[N],f[N],stack[N],key[N];
int get(int x){return ch[f[x]][1]==x;}
void updata(int x){xo[x]=xo[ch[x][0]]^xo[ch[x][1]]^key[x];}
void pushdown(int x)
{
if(delta[x])
{
swap(ch[x][0],ch[x][1]);
delta[ch[x][0]]^=1; delta[ch[x][1]]^=1;
delta[x]=0;
}
}
bool Is_root(int x){return ch[f[x]][0]!=x && ch[f[x]][1]!=x;}
void rotate(int x)
{
int old=f[x],oldf=f[old],which=get(x),gen=Is_root(old);
ch[old][which]=ch[x][which^1]; f[ch[x][which^1]]=old;
f[old]=x; ch[x][which^1]=old;
f[x]=oldf; if (!gen) ch[oldf][ch[oldf][1]==old]=x;
updata(old);
updata(x);
}
void splay(int x)
{
int top=0,i;
for (i=x;!Is_root(i);i=f[i]) stack[++top]=i;
stack[++top]=i;
for (i=top;i>=1;i--) pushdown(stack[i]);
for (;!Is_root(x);rotate(x))
if (!Is_root(f[x])) rotate(get(f[x])==get(x)?f[x]:x);
}
void access(int x)
{
int t=0;
for (;x;t=x,x=f[x])
{
splay(x);
ch[x][1]=t;
updata(x);
}
}
void reverse(int x)
{
access(x);
splay(x);
delta[x]^=1;
}
int find(int x)
{
int now=x;
while (ch[now][0]) now=ch[now][0];
return now;
}
bool connect(int x,int y)
{
access(x); splay(x);
int fa1=find(x);
access(y); splay(y);
int fa2=find(y);
if (fa1==fa2) return 1;
return 0;
}
void Link(int x,int y)
{
if (connect(x,y)) return;
reverse(x);
f[x]=y;
splay(x);
}
void Cut(int x,int y)
{
if (!connect(x,y)) return;
reverse(x);
access(y);
splay(y);
ch[y][0]=f[x]=0;
}
int qurry(int x,int y)
{
reverse(x);
access(y);
splay(y);
return xo[y];
}
int main()
{
int n,m,i,id;
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++) scanf("%d",&key[i]);
while (m--)
{
int x,y;
scanf("%d%d%d",&id,&x,&y);
if (id==0) printf("%d\n",qurry(x,y));
else if (id==1) Link(x,y);
else if (id==2) Cut(x,y);
else {key[x]=y; access(x);}
}
}
tip:
在区间里查询值的做法:把一个端点reverse到根,然后把另一个端点access+splay到顶点,这时候顶点维护的值就是我们要的值,因为不属于这个区间内的点(也就是不属于这条链上的)根本就不是这棵splay的儿子,值根本不会被记录进去