首页 > 技术文章 > BZOJ3282Tree——LCT

Khada-Jhin 2018-10-05 13:55 原文

题目描述

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

输出

对于每一个0号操作,你须输出X到Y的路径上点权的Xor和。

样例输入

3 3
1
2
3
1 1 2
0 1 2
0 1 1

样例输出

3
1
 
LCT模板题,splay维护子树异或和即可。因为cut时不保证边存在,所以注意cut时的判断。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int x,y;
int opt;
int v[300010];
int f[300010];
int s[300010][2];
int st[300010];
int r[300010];
int sum[300010];
int get(int rt)
{
    return rt==s[f[rt]][1];
}
void pushup(int rt)
{
    sum[rt]=v[rt]^sum[s[rt][0]]^sum[s[rt][1]];
}
void pushdown(int rt)
{
    if(r[rt])
    {
        swap(s[rt][0],s[rt][1]);
        r[s[rt][0]]^=1;
        r[s[rt][1]]^=1;
        r[rt]^=1;
    }
}
int is_root(int rt)
{
    return s[f[rt]][0]!=rt&&s[f[rt]][1]!=rt;
}
void rotate(int rt)
{
    int fa=f[rt];
    int anc=f[fa];
    int k=get(rt);
    if(!is_root(fa))
    {
        s[anc][fa==s[anc][1]]=rt;
    }
    s[fa][k]=s[rt][k^1];
    f[s[fa][k]]=fa;
    s[rt][k^1]=fa;
    f[fa]=rt;
    f[rt]=anc;
    pushup(fa);
    pushup(rt);
}
void splay(int rt)
{
    int top=0;
    st[++top]=rt;
    for(int i=rt;!is_root(i);i=f[i])
    {
        st[++top]=f[i];
    }
    for(int i=top;i>=1;i--)
    {
        pushdown(st[i]);
    }
    for(int fa;!is_root(rt);rotate(rt))
    {
        if(!is_root(fa=f[rt]))
        {
            rotate(get(rt)==get(fa)?fa:rt);
        }
    }
}
void access(int rt)
{
    for(int x=0;rt;x=rt,rt=f[rt])
    {
        splay(rt);
        s[rt][1]=x;
        pushup(rt);
    }
}
void reverse(int rt)
{
    access(rt);
    splay(rt);
    r[rt]^=1;
}
int find(int rt)
{
    access(rt);
    splay(rt);
    while(s[rt][0])
    {
        rt=s[rt][0];
    }
    return rt;
}
void link(int x,int y)
{
    reverse(x);
    f[x]=y;
}
void cut(int x,int y)
{
    reverse(x);
    access(y);
    splay(y);
    if(s[x][1]||f[x]!=y||s[y][get(x)^1])
    {
        return ;
    }
    s[y][0]=f[x]=0;
}
void change(int rt,int x)
{
    v[rt]=x;
    access(rt);
    splay(rt);
}
int query(int x,int y)
{
    reverse(x);
    access(y);
    splay(y);
    return sum[y];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&v[i]);
    }
    while(m--)
    {
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==0)
        {
            printf("%d\n",query(x,y));
        }
        else if(opt==1&&find(x)!=find(y))
        {
            link(x,y);
        }
        else if(opt==2&&find(x)==find(y))
        {
            cut(x,y);
        }
        else if(opt==3)
        {
            change(x,y);
        }
    }
}

推荐阅读