SPLAY,LCT学习笔记(六)

6 篇文章 0 订阅
3 篇文章 0 订阅

这应该暂时是个终结篇了...

最后在这里讨论LCT的一个常用操作:维护虚子树信息

这也是一个常用操作

下面我们看一下如何来维护

以下内容转自https://blog.csdn.net/neither_nor/article/details/52979425

对于一个点x,如果我们对x进行access操作,那么他的虚子树内将包含且仅包含他原树中子树内除了他自己以外的所有点,这时如果我们维护了他的虚子树信息和,我们把这个信息与他自己的信息合并,我们就得到了他在原树中的子树信息

在下面的讨论中,我们发现我们可以同时维护一个点的虚子树信息和LCT子树信息来达到维护虚子树信息的目的

考虑一个点的虚子树信息会在什么情况下发生改变,一个点的虚子树信息改变,当且仅当进行link或者access操作时。

在进行access操作时,我们会有更换一个点的x右儿子的操作,这时我们要把x原来的右儿子的LCT子树信息加入x的虚子树信息,把x的新的右儿子的LCT子树信息从x的虚子树信息中减去

在进行link操作时,我们会先把点x换根,然后连一条x到y的虚边,这时我们发现不仅y的虚子树信息需要加入x的LCT子树信息,y的所有祖先的LCT子树信息也需要更改,而这样我们就没法维护了,所以在进行link操作的时候我们需要把y也换根(其实access再splay就行了,不用换成根),这样就只会对y的虚子树信息和LCT子树信息产生影响

我们还需要维护一个x的LCT子树的信息和,x的LCT子树的信息和就等于x的实儿子的LCT子树信息和加上x的虚子树的信息和加上x自己,在splay的update函数中就可以直接维护

这样我们就完成了对子树信息的维护

换根操作、cut操作和链修改操作并不影响我们上边的讨论,所以也是兹磁的

转载结束

例:bzoj 4530大融合

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
int c[100005][2];
int f[100005];
bool ttag[100005];
int si[100005];
int s[100005];
void update(int rt)
{
    s[rt]=s[c[rt][0]]+s[c[rt][1]]+si[rt]+1;
}
bool berot(int rt)
{
    if(c[f[rt]][0]==rt||c[f[rt]][1]==rt)
    {
        return 0;
    }
    return 1;
}
void reverse(int rt)
{
    swap(c[rt][0],c[rt][1]);
    ttag[rt]^=1;
}
void pushdown(int rt)
{
    if(ttag[rt])
    {
        if(c[rt][0])
        {
            reverse(c[rt][0]);
        }
        if(c[rt][1])
        {
            reverse(c[rt][1]);
        }
        ttag[rt]=0;
    }
} 
void repush(int rt)
{
    if(!berot(rt))
    {
        repush(f[rt]);
    }
    pushdown(rt);
}
void rotate(int rt)
{
    int ltyp=0;
    int fa=f[rt];
    int ffa=f[fa];
    if(c[fa][1]==rt)
    {
        ltyp=1;
    }
    if(!berot(fa))
    {
        if(c[ffa][0]==fa)
        {
            c[ffa][0]=rt;
        }else
        {
            c[ffa][1]=rt;
        }
    }
    c[fa][ltyp]=c[rt][ltyp^1];
    c[rt][ltyp^1]=fa;
    f[c[fa][ltyp]]=fa;
    f[fa]=rt;
    f[rt]=ffa;
    update(fa);
}
void splay(int rt)
{
    repush(rt);
    while(!berot(rt))
    {
        int fa=f[rt];
        int ffa=f[fa];
        int jr=f[ffa];
        if(!berot(fa))
        {
            if((c[fa][0]==rt&&c[ffa][0]!=fa)||(c[fa][1]==rt&&c[ffa][1]!=fa))
            {
                rotate(rt);
            }else
            {
                rotate(fa);
            }
        }
        rotate(rt);
    }
    update(rt);
}
void access(int rt)
{
    int y=0;
    while(rt)
    {
        splay(rt);
        si[rt]+=s[c[rt][1]];
        c[rt][1]=y;
        si[rt]-=s[c[rt][1]];
        update(rt);
        y=rt;
        rt=f[rt];
    }
}
void makeroot(int rt)
{
    access(rt);
    splay(rt);
    reverse(rt);
}
void split(int st,int ed)
{
    makeroot(st);
    access(ed);
    splay(ed);
}
void link(int st,int ed)
{
    split(st,ed);
    f[st]=ed;
    si[ed]+=s[st];
    update(ed);
}

inline int read()
{
    int f=1,x=0;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;
}
int n,q;
char ss[5];
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        s[i]=1;
    }
    while(q--)
    {
        scanf("%s",ss);
        int x=read(),y=read();
        if(ss[0]=='A')
        {
            link(x,y);
        }else
        {
            split(x,y);
            printf("%lld\n",(long long)(si[x]+1)*(long long)(si[y]+1));
        }
    }
    return 0;
}

例:bzoj 3510首都

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
int c[100005][2];
int f[100005];
int ff[100005];
int s[100005];
int si[100005];
bool ttag[100005];
int tot=0;
int findf(int x)
{
    if(x==ff[x])
    {
        return x;
    }
    return ff[x]=findf(ff[x]);
}
void update(int rt)
{
    s[rt]=s[c[rt][0]]+s[c[rt][1]]+si[rt]+1;
}
bool berot(int rt)
{
    if(c[f[rt]][0]==rt||c[f[rt]][1]==rt)
    {
        return 0;
    }
    return 1;
}
void reverse(int rt)
{
    swap(c[rt][0],c[rt][1]);
    ttag[rt]^=1;
}
void pushdown(int rt)
{
    if(ttag[rt])
    {
        reverse(c[rt][0]);
        reverse(c[rt][1]);
        ttag[rt]=0;
    }
}
void repush(int rt)
{
    if(!berot(rt))
    {
        repush(f[rt]);
    }
    pushdown(rt);
}
void rotate(int rt)
{
    int ltyp=0;
    int fa=f[rt];
    int ffa=f[fa];
    if(c[fa][1]==rt)
    {
        ltyp=1;
    }
    if(!berot(fa))
    {
        if(c[ffa][1]==fa)
        {
            c[ffa][1]=rt;
        }else
        {
            c[ffa][0]=rt;
        }
    }
    c[fa][ltyp]=c[rt][ltyp^1];
    c[rt][ltyp^1]=fa;
    f[c[fa][ltyp]]=fa;
    f[fa]=rt;
    f[rt]=ffa;
    update(fa);
}
void splay(int rt)
{
    repush(rt);
    while(!berot(rt))
    {
        int fa=f[rt];
        int ffa=f[fa];
        if(!berot(fa))
        {
            if((c[fa][0]==rt&&c[ffa][0]!=fa)||(c[fa][1]==rt&&c[ffa][1]!=fa))
            {
                rotate(rt);
            }else
            {
                rotate(fa);
            }
        }
        rotate(rt);
    }
    update(rt);
}
void access(int rt)
{
    int y=0;
    while(rt)
    {
        splay(rt);
        si[rt]+=s[c[rt][1]];
        c[rt][1]=y;
        si[rt]-=s[c[rt][1]];
        update(rt);
        y=rt;
        rt=f[rt];
    }
}
void makeroot(int rt)
{
    access(rt);
    splay(rt);
    reverse(rt);
}
void split(int st,int ed)
{
    makeroot(st);
    access(ed);
    splay(ed);
}
void link(int st,int ed)
{
    split(st,ed);
    f[st]=ed;
    si[ed]+=s[st];
    update(ed);
}
int query(int rt)
{
    int ls=0,rs=0,ltemp=0,rtemp=0;
    int ed=s[rt]>>1;
    bool flag=s[rt]%2;
    int ret=0x3f3f3f3f;
    while(rt)
    {
        pushdown(rt);
        int lc=c[rt][0];
        int rc=c[rt][1];
        ltemp=ls+s[lc];
        rtemp=rs+s[rc];
        if(ltemp<=ed&&rtemp<=ed)
        {
            if(flag)
            {
                ret=rt;
                break;
            }else if(rt<ret)
            {
                ret=rt;
            }
        }
        if(ltemp<rtemp)
        {
            ls+=s[lc]+si[rt]+1;
            rt=rc;
        }else
        {
            rs+=s[rc]+si[rt]+1;
            rt=lc;
        }
    }
    splay(ret);
    return ret;
}
inline int read()
{
    int f=1,x=0;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;
}
int n,m;
char ss[10];
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    {
        tot^=i;
        s[i]=1;
        ff[i]=i;
    }
    while(m--)
    {
        scanf("%s",ss);
        if(ss[0]=='A')
        {
            int x=read(),y=read();
            link(x,y);
            int f1=findf(x);
            int f2=findf(y);
            split(f1,f2);
            int rf=query(f2);
            tot=tot^f1^f2^rf;
            ff[f1]=ff[f2]=ff[rf]=rf;
        }else if(ss[0]=='Q')
        {
            int x=read();
            printf("%d\n",findf(x));
        }else
        {
            printf("%d\n",tot);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值