[BZOJ3282] Tree

11 篇文章 0 订阅
1 篇文章 0 订阅

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板子题qvq

#include <bits/stdc++.h>
#define N 300010
#define Lc cur->ch[0]
#define Rc cur->ch[1]
#define rep(i,l,r) for (int i=l;i<=r;i++)
using namespace std;
int n,m;
struct node{
    int x,s,size; bool rev;
    node *ch[2],*fa,*parent;
}t[N];

template <class Aqua>
inline void read(Aqua &s){
    s=0; Aqua f=1; char c=getchar();
    while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();}
    while (isdigit(c)) s=s*10+c-'0',c=getchar();
    s*=f;
}

inline int get(node *cur){
    return (cur->fa->ch[0]==cur)?0:1;
}

inline void update(node *cur){
    cur->size=Lc->size+Rc->size+1;
    cur->s=cur->x^Lc->s^Rc->s;
}

inline void pushdown(node *cur){
    if (cur->rev){
        cur->rev=0;
        swap(Lc,Rc);
        Lc->rev^=1,Rc->rev^=1;
    }
}

void rotate(node *cur){
    pushdown(cur->fa),pushdown(cur);
    node *fa=cur->fa; int x=get(cur);
    cur->fa=fa->fa; fa->fa->ch[get(fa)]=cur;
    fa->ch[x]=cur->ch[x^1]; cur->ch[x^1]->fa=fa;
    cur->ch[x^1]=fa; fa->fa=cur;
    update(fa),update(cur);
    cur->parent=fa->parent; fa->parent=t;
}

void splay(node *cur){
    for (;cur->fa!=t;rotate(cur))
        if (cur->fa->fa!=t)
            rotate(get(cur)^get(cur->fa)?cur:cur->fa);
    pushdown(cur);
}

void access(node *cur){
    splay(cur);
    Rc->fa=t;
    Rc->parent=cur; Rc=t;
    update(cur);
    for (node *v;cur->parent!=t;cur->fa=v,cur=v){
        splay(v=cur->parent);
        v->ch[1]->fa=t; v->ch[1]->parent=v;
        v->ch[1]=cur; update(v);
    }
}

void evert(node *cur){
    access(cur);
    splay(cur);
    cur->rev^=1;
    pushdown(cur);
}

int find(node *cur){
    access(cur);
    splay(cur);
    for (;;pushdown(cur=Lc))
        if (Lc==t)
            return (cur-t);
}

void link(node *u,node *v){
    evert(u);
    access(v);
    splay(v);
    u->ch[0]->fa=t; u->ch[0]->parent=u;
    u->ch[0]=v; v->fa=u; update(u);
}

void cut(node *u,node *v){
    evert(u);
    access(v);
    splay(v);
    if (v->ch[0]!=u || u->size!=1)
        return;
    v->ch[0]=t; update(v);
    u->fa=u->parent=t;
}

int query(node *u,node *v){
    evert(u);
    access(v);
    splay(v);
    return v->ch[0]->s^v->x;
}

void pre(){
    node *cur=t;
    cur->size=cur->rev=0;
    cur->ch[0]=cur->ch[1]=cur->fa=cur->parent=t;
    rep(i,1,n){
        cur=t+i; read(cur->x);
        cur->size=1; cur->rev=0;
        cur->ch[0]=cur->ch[1]=cur->fa=cur->parent=t;
    }
}

int main(){
    read(n),read(m);
    pre();
    int opt,u,v;
    rep(i,1,m){
        read(opt),read(u),read(v);
        if (!opt)
            printf("%d\n",query(t+u,t+v));
        if (opt==1)
            if (find(t+u)!=find(t+v))
                link(t+u,t+v);
        if (opt==2)
            cut(t+u,t+v);
        if (opt==3)
            (t+u)->x=v,splay(t+u);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值