LCT(Link-Cut Tree)

Link-cut tree(LCT)【可以理解为树链剖分+splay】

给出如下定义:

  access(x):访问x节点

  perferred child:若以x为根的子树中最后被访问的节点在以x的儿子y为根的子树中,则称y为节点x的preferred child

  preferred edge:节点x与其preferred child之间的边

  preferred path:由preferred edge组成的路径

每条preferred path用splay维护,记录splay的根接到上条重链的哪个节点

操作

  每次访问一个点时,该点一直到根的路径上的点全部被修改,与preferred child断开并连到新的preferred child上,并打上翻转标记,也就是拆分(cut)和合并(link)两个操作,其余链上的维护可以通过下传标记(pushdown)解决

例题:

  bzoj2002弹飞绵羊

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mx=200010; 
int n,m,fa[Mx],l[Mx],r[Mx],root[Mx],siz[Mx],rev[Mx];
void pushup(int x) { siz[x]=siz[l[x]]+siz[r[x]]+1; }
void pushdown(int x) { if(rev[x]) rev[x]^=1,rev[l[x]]^=1,rev[r[x]]^=1,swap(l[x],r[x]); }
void rotate(int x)
{
    int y=fa[x];
    if(l[y]==x) l[y]=r[x],fa[r[x]]=y,r[x]=y,fa[x]=fa[y],fa[y]=x;
    else r[y]=l[x],fa[l[x]]=y,l[x]=y,fa[x]=fa[y],fa[y]=x;
    if(root[y]) root[y]=0,root[x]=1;
    else
        if(r[fa[x]]==y) r[fa[x]]=x;
        else l[fa[x]]=x;
    pushup(y);
}
void splay(int x)
{
    while(!root[x])
    {
        int y=fa[x],yy=fa[y];
        if(root[y]) rotate(x);
        else
            if((l[yy]==y&&l[y]!=x)||(l[yy]!=y&&l[y]==x)) rotate(y),rotate(x);
            else rotate(x),rotate(x);
    }
    pushup(x);
}
void access(int x)
{
    int y=0;
    while(x)
    {
        splay(x); root[r[x]]=1,root[y]=0;
        pushup(x); r[x]=y,y=x,x=fa[x];
    }
}
void rever(int x) { access(x); splay(x); rev[x]^=1; }
void link(int x,int y) { rever(x); fa[l[x]]=0,root[l[x]]=1,l[x]=0,fa[x]=y; pushup(x); }
void cut(int x,int y) { rever(x); access(y); splay(y); l[y]=0,fa[x]=0; }
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) root[i]=1,siz[i]=1;
    for(int i=1;i<=n;i++)
    {
        int x; scanf("%d",&x);
        if(i+x<=n) link(i,i+x);
    }
    scanf("%d",&m);
    while(m--)
    {
        int num,x,k; scanf("%d",&num);
        if(num==1)
        {
            scanf("%d",&x); x++; 
            rever(x);
            printf("%d
",siz[l[x]]+1);
        }
        else
        {
            scanf("%d%d",&x,&k); x++;
            if(x+k>n) link(x,0);
            else link(x,x+k);
        }
    } 
}

  bzoj2631 tree

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mx=200010;
const int p=51061;
int n,top,q[Mx],fa[Mx],son[Mx][2],siz[Mx],rev[Mx];
unsigned int val[Mx],sum[Mx],add_tag[Mx],mul_tag[Mx];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void cal(int x,int a,int b)
{
    if(!x) return ;
    val[x]=(a*val[x]+b)%p;
    sum[x]=(a*sum[x]+b*siz[x])%p;
    add_tag[x]=(a*add_tag[x]+b)%p;
    mul_tag[x]=(a*mul_tag[x])%p;
}
int isroot(int x)
{
    if(son[fa[x]][0]!=x&&son[fa[x]][1]!=x) return 1;
    return 0;
}
void pushup(int x)
{
    int l=son[x][0],r=son[x][1];
    sum[x]=(sum[l]+sum[r]+val[x])%p;
    siz[x]=(siz[l]+siz[r]+1)%p;
}
void pushdown(int x)
{
    int l=son[x][0],r=son[x][1];
    if(rev[x])
        rev[x]^=1,rev[l]^=1,rev[r]^=1,
        swap(son[x][0],son[x][1]);
    int a=add_tag[x],m=mul_tag[x];
    add_tag[x]=0,mul_tag[x]=1;
    if(a!=0||m!=1) cal(l,m,a),cal(r,m,a);
}
void rotate(int x)
{
    int l=0,r=0,y=fa[x],yy=fa[y];
    if(son[y][1]==x) l=1; r=l^1;
    if(!isroot(y)) son[yy][(son[yy][1]==y)]=x;
    fa[x]=yy,fa[y]=x,fa[son[x][r]]=y,son[y][l]=son[x][r],son[x][r]=y;
    pushup(y);pushup(x);
}
void splay(int x)
{
    q[++top]=x;
    for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
    while(top) pushdown(q[top--]);
    while(!isroot(x))
    {
        int y=fa[x],yy=fa[y];
        if(!isroot(y))
        {
            if((son[y][0]==x)^(son[yy][0]==y)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
void access(int x)
{
    for(int t=0;x;t=x,x=fa[x])
        splay(x),son[x][1]=t,pushup(x);
}
void rever(int x)
{
    access(x); splay(x); rev[x]^=1;
}
void link(int x,int y)
{
    rever(x); fa[x]=y;
}
void split(int x,int y)
{
    rever(y); access(x); splay(x);
}
void cut(int x,int y)
{
    rever(x); access(y); splay(y);
    son[y][0]=fa[x]=0;
}
signed main()
{
    int m; scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) val[i]=sum[i]=mul_tag[i]=siz[i]=1;
    for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),link(x,y);
    while(m--)
    {
        char ch[10]; scanf("%s",ch); int x,y,c; x=read(),y=read();
        if(ch[0]=='+') c=read(),split(x,y),cal(x,1,c);
        if(ch[0]=='-') cut(x,y),x=read(),y=read(),link(x,y);
        if(ch[0]=='*') c=read(),split(x,y),cal(x,c,0);
        if(ch[0]=='/') split(x,y),printf("%d
",sum[x]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/xiaoxubi/p/6422151.html