BZOJ 3282 Tree link cut trees

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






竟然找到水题了……

结果洛谷上有这题,竟然贴了个很老旧的……于是大致整改了一下。



#include<bits/stdc++.h>
using namespace std;
int read(){
    int x=0,f=1;char ch=getchar();
    while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int 
    N=300005;
int n,m;
struct LCT{
    int val,xsum,pre,son[2];
	bool rev;
}tree[N];
bool isroot(int x){
    return tree[tree[x].pre].son[0]!=x &&
           tree[tree[x].pre].son[1]!=x;
}
void up(int x){
    if (x){
        tree[x].xsum=tree[x].val;
        if (tree[x].son[0]) tree[x].xsum^=tree[tree[x].son[0]].xsum;
        if (tree[x].son[1]) tree[x].xsum^=tree[tree[x].son[1]].xsum;
    }
}
void down(int x){
    if (x && tree[x].rev){
        swap(tree[x].son[0],tree[x].son[1]);
        tree[tree[x].son[0]].rev^=1;
        tree[tree[x].son[1]].rev^=1;
        tree[x].rev^=1;
    }
}
void Rotate(int x){  
    int y=tree[x].pre,z=tree[y].pre,l,r;  
    if (tree[y].son[0]==x) l=0; else l=1;  
    r=l^1;  
    if (!isroot(y))  
        if (tree[z].son[0]==y) tree[z].son[0]=x;  
            else tree[z].son[1]=x;  
    tree[x].pre=z,tree[y].pre=x;  
    tree[y].son[l]=tree[x].son[r];  
    tree[tree[x].son[r]].pre=y;  
    tree[x].son[r]=y;  
    up(y);  
}  
int stk[N];  
void splay(int x){  
    int top=1;stk[1]=x;  
    for (int i=x;!isroot(i);i=tree[i].pre)  
        stk[++top]=tree[i].pre;  
    while (top) down(stk[top--]);  
    while (!isroot(x)){  
        int y=tree[x].pre,z=tree[y].pre;  
        if (!isroot(y))  
            if (tree[y].son[0]==x^tree[z].son[0]==y) Rotate(x);  
                else Rotate(y);  
        Rotate(x);  
    }  
    up(x);  
}  
void access(int x){
	for (int t=0;x;t=x,x=tree[x].pre)
    	splay(x),tree[x].son[1]=t,up(x);
}
void makeroot(int x){
    access(x),splay(x);
    tree[x].rev^=1;
}
int findroot(int x){
    access(x),splay(x);
    while (tree[x].son[0]) x=tree[x].son[0];
    return x;
}
void split(int x,int y){
    makeroot(x);
    access(y),splay(y); 
}
void cut(int x,int y){
    split(x,y);
    tree[y].son[0]=tree[x].pre=0;
}
void link(int x,int y){
    makeroot(x);
    tree[x].pre=y;
}
int main(){
    n=read(),m=read();
    for (int i=1;i<=n;i++) tree[i].val=tree[i].xsum=read();
    int opt,x,y;
    while (m--){
        opt=read(),x=read(),y=read();
        if (!opt){
            split(x,y);
            printf("%d\n",tree[y].xsum);
        }
        if (opt==1 && findroot(x)!=findroot(y)) link(x,y);
        if (opt==2 && findroot(x)==findroot(y)) cut(x,y);
        if (opt==3){
            access(x),splay(x);
            tree[x].val=y;
            up(x);
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值