【bzoj3282】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行,每行三个整数,分别代表操作类型和操作所需的量。

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裸题

注意数据有可能不合法,在连边的时候要找根,重点是删边。

cut操作中,要先让一个点u为根,在access另一个点v,再对它splay,这样形成的splay只有它两个点。若它俩有边,则当前v的左儿子一定是u,u的右儿子一定没有。

不过此题好像只需要判断u和v是否在同一棵子树就可以A了……数据水……

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int SZ = 1000010;
const int INF = 1000000010;

struct node{
    node *f,*ch[2];
    int ans,v;
    bool rev;

    void maintain()
    {
        ans = ch[0] -> ans ^ ch[1] -> ans ^ v;
    }

    void setc(node *x,int d) { (ch[d] = x) -> f = this; }

    void pushdown();

    int dir() { return f -> ch[1] == this; }

    bool isroot() { return f -> ch[0] != this && f -> ch[1] != this; }
}T[SZ], *null, *tree[SZ];

int Tcnt = 0;

node* newnode(int x)
{
    node *k = T + (Tcnt ++);
    k -> ch[0] = k -> ch[1] = k -> f = null;
    k -> v = k -> ans = x;
    k -> rev = 0;
    return k;
}

void pushrev(node *p) { if(p == null) return; swap(p -> ch[0],p ->ch[1]); p -> rev ^= 1; }

void node :: pushdown()
{
    if(rev) { pushrev(ch[0]); pushrev(ch[1]); rev = 0; }
}


void rotate(node *p)
{
    node *fa = p -> f;
    int d = p -> dir();
    p -> f = fa -> f;
    if(!fa -> isroot()) p -> f -> ch[fa -> dir()] = p;
    fa -> ch[d] = p -> ch[d ^ 1];
    if(fa -> ch[d] != null) fa -> ch[d] -> f = fa;
    p -> setc(fa,d ^ 1);
    fa -> maintain(); p -> maintain();
}

node *S[SZ];

void pushpath(node *p)
{
    int top = 0;
    while(!p -> isroot()) S[++ top] = p,p = p -> f;
    S[++ top] = p;
    while(top) S[top --] -> pushdown();
}

void splay(node *p)
{
    pushpath(p);
    while(!p -> isroot())
    {
        if(p -> f -> isroot()) rotate(p);
        else
        {
            if(p -> dir() == p -> f -> dir()) rotate(p -> f),rotate(p);
            else rotate(p),rotate(p);
        }
    }
    p -> maintain();
}

void access(node *p)
{
    node *last = null;
    while(p != null)
    {
        splay(p);
        p -> ch[1] = last; p -> maintain();
        last = p;
        p = p -> f;
    }
}

void toroot(node *p)
{
    access(p); splay(p); pushrev(p);
}

void link(node *u,node *v)
{
    toroot(u); u -> f = v;
}

void cut(node *u,node *v)
{
    toroot(u);
    access(v);
    splay(v);
    if(v -> ch[0] == u && u -> ch[1] == null)
        v -> ch[0] = u -> f = null,v -> maintain();
}

void change(node *p,int v)
{
    access(p); splay(p); p -> v = v;
    p -> maintain();
}

node* find_root(node *p)
{
    while(p -> f != null) p = p -> f;
    return p;
}

int ask_xor(node *u,node *v)
{
    toroot(u);
    access(v);
    splay(v);
    return v -> ans;
}

void init() { null = newnode(0); }

int main()
{
    init();
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i ++)
    {
        int x;
        scanf("%d",&x);
        tree[i] = newnode(x);
    }
    while(m --)
    {
        int opt,u,v;
        scanf("%d%d%d",&opt,&u,&v);
        if(opt == 0) 
            printf("%d\n",ask_xor(tree[u],tree[v]));
        else if(opt == 1) 
        {
            if(find_root(tree[u]) != find_root(tree[v])) 
                link(tree[u],tree[v]);
        }
        else if(opt == 2)
        {
            if(find_root(tree[u]) == find_root(tree[v]))
                cut(tree[u],tree[v]);
        }
        else
        {
            change(tree[u],v);
        }
    }
    return 0;
}
/*

5 2333
1 2 3 4 5
1 1 2
1 1 3
2 2 3
0 2 3

*/

你可能感兴趣的:(【bzoj3282】Tree LCT)