【模板】Link Cut Tree (动态树) LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

安利大佬的讲解:

LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

题目传送:【模板】Link Cut Tree (动态树)(luogu)

Description

写一种数据结构,支持更改节点权值,连边,删边,查询两点间路径上节点权值异或和

Solution

讲解大佬已经讲得很明白了

此处补充一点容易蒟蒻认为跳坑的细节(以他的代码为例)

  • fa [ ]储存的是原树上的父亲信息,但在一个splay中是打乱的,只能确定每个splay中序遍历第一点的原树父亲是fa[ 本棵splay树的根 ]
  • link( x , y )中必须写 f [ x ]=y,而不能写 f[ y ]=x,因为y可能已经存储了splay上的父亲信息,而x为splay树的根
  • 注意splay函数和rotate函数和传统写法的不同,LCT中对0的处理更苛刻

Code本人模板(强行往自己的传统写法上靠...)

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N=1e5+10;
int fa[N],ch[N][2];
int s[N],d[N],n,m,opt,x,y,rev[N];
bool nroot(int x)
{
    return x==ch[fa[x]][0] || x==ch[fa[x]][1];
}
int get(int x)
{
    return x==ch[fa[x]][1];
}
void push_up(int x)
{
    s[x]=s[ch[x][0]]^s[ch[x][1]]^d[x];
}
void change(int x)
{
    swap(ch[x][0],ch[x][1]);
    rev[x]^=1;
}
void push_down(int x)
{
    if(rev[x])
    {
        change(ch[x][0]);
        change(ch[x][1]);
        rev[x]=0;
    }
}
void dfs(int x)
{
    if(nroot(x)) dfs(fa[x]);
    push_down(x);
}
void rotate(int x)
{
    int y=fa[x],z=fa[y],wh=get(x);
    if(nroot(y)) ch[z][get(y)]=x;
    if(ch[x][wh^1]) fa[ch[x][wh^1]]=y;
    ch[y][wh]=ch[x][wh^1];
    ch[x][wh^1]=y;
    fa[y]=x,fa[x]=z;
    push_up(y),push_up(x);
}
void splay(int x)
{
    dfs(x);
    for(int fx;fx=fa[x],nroot(x);rotate(x))
        if(nroot(fx)) rotate(get(x)==get(fx)?fx:x);
}
void access(int x)
{
    for(int y=0;x;x=fa[y=x])
        splay(x),ch[x][1]=y,push_up(x);
}
void makeroot(int x)
{
    access(x),splay(x);
    change(x);
}
int findroot(int x)
{
    access(x),splay(x);
    while(ch[x][0]) push_down(x),x=ch[x][0];
    splay(x);
    return x;
}
void link(int x,int y)
{
    makeroot(x);
    if(findroot(y)!=x) fa[x]=y;
}
void cut(int x,int y)
{
    makeroot(x);
    if(findroot(y)==x && fa[y]==x && !ch[y][0])
        fa[y]=ch[x][1]=0;
}
void split(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&d[i]);
    while(m--)
    {
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==0) split(x,y),printf("%d\n",s[y]);
        else if(opt==1) link(x,y);
        else if(opt==2) cut(x,y);
        else splay(x),d[x]=y,push_up(x);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hsez-cyx/p/12287331.html