Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 2119 Solved: 973
Description
给定N个点以及每个点的权值,要你处理接下来的M个操作。操作有4种。操作从0到3编号。点从1到N编号。
0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和。保证x到y是联通的。
1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接。
2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在。
3:后接两个整数(x,y),代表将点X上的权值变成Y。
Input
第1行两个整数,分别为N和M,代表点数和操作数。
第2行到第N+1行,每行一个整数,整数在[1,10^9]内,代表每个点的权值。
第N+2行到第N+M+1行,每行三个整数,分别代表操作类型和操作所需的量。
Output
对于每一个0号操作,你须输出X到Y的路径上点权的Xor和。
Sample Input
3 3
1
2
3
1 1 2
0 1 2
0 1 1
Sample Output
3
1
HINT
1<=N,M<=300000
Source
动态树
裸LCT,如果不会LCT的朋友可以以这道题为LCT第一题,因为非常的裸,还可以看我的LCT讲解
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
const int MAXN=300010;
using namespace std;
struct Tree{
int child[2],sum,val,fa,rev;
}tree[MAXN];
int n,Q,opt,xx,yy;
void pushup(int x){tree[x].sum=tree[tree[x].child[0]].sum^tree[tree[x].child[1]].sum^tree[x].val;}
void pushdown(int x){
if(tree[x].rev){
tree[x].rev^=1;
tree[tree[x].child[0]].rev^=1;
tree[tree[x].child[1]].rev^=1;
swap(tree[x].child[0],tree[x].child[1]);
}
}
bool isroot(int x){
return (tree[tree[x].fa].child[0]!=x)&&(tree[tree[x].fa].child[1]!=x);
}
void Pushdown(int x){
if(!isroot(x)) Pushdown(tree[x].fa);
pushdown(x);
}
void rotate(int x){
int y=tree[x].fa,z=tree[y].fa,l,r;
if(tree[y].child[0]==x) l=0;else l=1;r=l^1;
if(!isroot(y)){
if(tree[z].child[0]==y)tree[z].child[0]=x;
else tree[z].child[1]=x;
}
tree[x].fa=z;tree[y].fa=x;tree[tree[x].child[r]].fa=y;
tree[y].child[l]=tree[x].child[r];tree[x].child[r]=y;
pushup(y);pushup(x);
}
void splay(int x){
Pushdown(x);
while(!isroot(x)){
int y=tree[x].fa,z=tree[y].fa;
if(!isroot(y)){
if((tree[y].child[0]==x)^(tree[z].child[0]==y)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x){for(register int i=0;x;i=x,x=tree[x].fa){splay(x);tree[x].child[1]=i;pushup(x);}}
void reverse(int x){access(x);splay(x);tree[x].rev^=1;}
int findroot(int x){access(x);splay(x);while(tree[x].child[0])x=tree[x].child[0];return x;}
void link(int x,int y){reverse(x);tree[x].fa=y;}
void cnt(int x,int y){reverse(x);access(y);splay(y);if(tree[y].child[0]==x) tree[y].child[0]=tree[x].fa=0;}
int main(){
scanf("%d%d",&n,&Q);
for(register int i=1;i<=n;i++)scanf("%d",&tree[i].val),tree[i].sum=tree[i].val;
while(Q--){
scanf("%d%d%d",&opt,&xx,&yy);
switch(opt){
case 0:reverse(xx);access(yy);splay(yy); printf("%d\n",tree[yy].sum);break;
case 1:if(findroot(xx)!=findroot(yy)) link(xx,yy);break;
case 2:if(findroot(xx)==findroot(yy)) cnt(xx,yy);break;
case 3:access(xx);splay(xx);tree[xx].val=yy;pushup(xx);break;
}
}
return 0;
}