Luogu 3690 Link Cut Tree

  • \(LCT\) 模板题.可以参考讲解和这份码风(个人认为)良好的代码.
  • 注意用 \(set\) 来维护实际图中两点是否有直接连边,否则无脑 \(Link/Cut\) 会崩掉.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pii pair<int,int>
inline int read()
{
    int x=0;
    bool pos=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            pos=0;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return pos?x:-x;
}
const int MAXN=3e5+10;
struct node{
    int val,sum,rev;
    int ch[2],fa;
    node()
        {
            rev=0;
            val=sum=0;
        }
}tree[MAXN];//splay以原图中的深度为关键字. 
set<int> Link[MAXN];//维护两点是否有边相连
int n,m,stk[MAXN],tp=0;
#define root tree[x]
#define lson tree[tree[x].ch[0]]
#define rson tree[tree[x].ch[1]]
void pushup(int x)
{
    root.sum=lson.sum^root.val^rson.sum;
}
void inverse(int x)
{
    swap(tree[x].ch[0],tree[x].ch[1]);
    root.rev^=1;
}
void pushdown(int x)
{
    if(root.rev)
        {
            if(root.ch[0])
                inverse(root.ch[0]);
            if(root.ch[1])
                inverse(root.ch[1]);
            root.rev=0;
        }
}
bool isroot(int x)
{
    return tree[root.fa].ch[0]!=x && tree[root.fa].ch[1]!=x;
}
void rotate(int x)
{
    int y=tree[x].fa,z=tree[y].fa;
    int k=tree[y].ch[1]==x;
    if(!isroot(y))
        tree[z].ch[tree[z].ch[1]==y]=x;
    tree[x].fa=z;//splay中,根的父亲是原图中链顶(该节点)的父亲 
    tree[y].ch[k]=tree[x].ch[k^1];
    tree[tree[x].ch[k^1]].fa=y;
    tree[x].ch[k^1]=y;
    tree[y].fa=x;
    pushup(y);
}
void splay(int x)
{
    stk[++tp]=x;
    for(int pos=x;!isroot(pos);pos=tree[pos].fa)
        stk[++tp]=tree[pos].fa;
    while(tp)
        pushdown(stk[tp--]);//因为要从下往上转,所以先将从x到splay根节点上的标记全部下传 
    while(!isroot(x))
        {
            int y=tree[x].fa,z=tree[y].fa;
            if(!isroot(y))
                (tree[y].ch[0]==x)^(tree[z].ch[0]==y)?rotate(x):rotate(y);
            rotate(x);
        }
    pushup(x);
}
void Access(int x)
{
    for(int y=0;x;y=x,x=tree[x].fa)
        {
            splay(x);
            tree[x].ch[1]=y;
            pushup(x);
        }
}
void makeroot(int x)
{
    Access(x);
    splay(x);
    inverse(x);
}
int findroot(int x)
{
    Access(x);
    splay(x);//翻转后找深度最小的,就是原来深度最大的. 
    while(tree[x].ch[0])
        x=tree[x].ch[0];
    return x;
}
void split(int x,int y)
{
    makeroot(x);
    Access(y);//x到y是一颗splay 
    splay(y);//然后就是y及其左子树存储的信息了. (实际上就是y,因为它没有右子树)
}
void link(int x,int y)
{
    if(Link[x].find(y)!=Link[x].end())
        return;
    makeroot(x);
    tree[x].fa=y;//连一条虚边 
    Link[x].insert(y);
    Link[y].insert(x);
}
void cut(int x,int y)
{
    if(Link[x].find(y)==Link[x].end())
        return;
    split(x,y);//在splay中从y一直往左走到x.
    tree[y].ch[0]=0;
    tree[x].fa=0;
    Link[x].erase(y);
    Link[y].erase(x); 
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;++i)
        tree[i].val=tree[i].sum=read();//原图编号即splay标号
    while(m--)
        {
            int op=read(),x=read(),y=read();
            if(op==0)
                {
                    split(x,y);
                    printf("%d\n",tree[y].sum);
                }
            else if(op==1)
                {
                    link(x,y);
                }
            else if(op==2)
                {
                    cut(x,y);
                }
            else
                {
                    Access(x);
                    splay(x);//这样不用修改splay中其他节点信息 
                    tree[x].val=y;
                    pushup(x);
                }
        }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/jklover/p/10388880.html