P3690 【模板】Link Cut Tree (动态树)

题目背景

动态树

题目描述

给定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。

输入输出格式

输入格式:

 

第1行两个整数,分别为n和m,代表点数和操作数。

第2行到第n+1行,每行一个整数,整数在[1,10^9]内,代表每个点的权值。

第n+2行到第n+m+1行,每行三个整数,分别代表操作类型和操作所需的量。

 

输出格式:

 

对于每一个0号操作,你须输出x到y的路径上点权的xor和。

 

输入输出样例

输入样例#1: 复制
3 3 
1
2
3
1 1 2
0 1 2 
0 1 1
输出样例#1: 复制
3
1

说明

数据范围: 1 \leq N, M \leq 3 \cdot {10}^51N,M3105

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

const int N=3e5+5;

inline int read()
{
    char c=getchar();int num=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
        num=num*10+c-'0';
    return num;
}

int f[N],c[N][2],v[N],s[N],st[N];
bool r[N];    //翻转标记 

inline bool nroot(int x)    //判断是不是root 
{
    return c[f[x]][0]==x||c[f[x]][1]==x;
}

inline void pushup(int x)    //更新siz 
{
    s[x]=s[c[x][0]]^s[c[x][1]]^v[x];
}

inline void pushr(int x)        //翻转操作 
{
    int t=c[x][0];c[x][0]=c[x][1];c[x][1]=t;
    r[x]^=1;
}

inline void pushdown(int x)
{
    if(r[x])
    {
        if(c[x][0])
            pushr(c[x][0]);
        if(c[x][1])
            pushr(c[x][1]);
        r[x]=0;
    }
}

inline void rotate(int x)    //旋转rotate 
{
    int y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
    if(nroot(y))
        c[z][c[z][1]==y]=x;
    c[x][!k]=y,c[y][k]=w;
    if(w)
        f[w]=y;
    f[y]=x,f[x]=z;
    pushup(y);
}

inline void splay(int x)
{
    int y=x,z=0;
    st[++z]=y;
    while(nroot(y))
        st[++z]=y=f[y];
    while(z)
        pushdown(st[z--]);
    while(nroot(x))
    {
        y=f[x],z=f[y];
        if(nroot(y))
            rotate((c[y][0]==x)^(c[z][0]==y)?x:y);
        rotate(x); 
    }
    pushup(x);
}

inline void access(int x)
{
    for(int y=0;x;x=f[y=x])
        splay(x),c[x][1]=y,pushup(x);
}

inline void makeroot(int x)
{
    access(x),splay(x);
    pushr(x);    //把它的左儿子调到右儿子 
}

inline int findroot(int x)
{
    access(x),splay(x);
    while(c[x][0])
        pushdown(x),x=c[x][0];
    return x;
}

inline void split(int x,int y)    //提取路径 
{
    makeroot(x);
    access(y),splay(y);
}

inline void link(int x,int y)    //连边 
{
    makeroot(x);
    if(findroot(y)!=x)
        f[x]=y;
}

inline void cut(int x,int y)
{
    makeroot(x);
    if(findroot(y)==x&&f[x]==y&&!c[x][1])
    {
        f[x]=c[y][0]=0;
        pushup(y);
    }
}

int n,m,type,x,y;
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;++i)
        v[i]=read();
    while(m--)
    {
        type=read(),x=read(),y=read();
        switch(type)
        {
            case 0:
                split(x,y);printf("%d\n",s[y]);break;
            case 1:
                link(x,y);break;
            case 2:
                cut(x,y);break;
            case 3:
                splay(x);v[x]=y;
        }
    }
    return 0;
}

 

posted @ 2018-09-12 11:36  whymhe  阅读(218)  评论(0编辑  收藏  举报