BZOJ_3282_Tree_LCT

BZOJ_3282_Tree_LCT

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行,每行三个整数,分别代表操作类型和操作所需的量。
1<=N,M<=300000

 

 

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

 LCT维护一下点权的xor和,单点修改直接暴力。
修改的时候应该是不用access,但我加上access操作会快一些
 
代码:
#include <stdio.h>
#include <string.h>
#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) {
    /*access(x);*/ 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);
        }
    }
}

 

posted @ 2018-04-29 21:50  fcwww  阅读(241)  评论(0编辑  收藏  举报