[BZOJ2002][Hnoi2010]Bounce 弹飞绵羊(LCT)

本文详细解析了一道关于LCT(链剖树)的数据结构题目,介绍了如何利用辅助树进行节点操作,包括旋转、翻转等,并通过代码实现查询特定节点的左子树大小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

我是超链接

题解:

这就是一道LCT的裸题啦
这里的f[x]表示在辅助树中x的father,a[x]则表示在原树中x的father
询问的时候先将n+1换成根,然后access x,然后将x splay到根,这样x左子树的大小就是答案

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N=200005;
int size[N],deltaz[N],f[N],stack[N],n,a[N],ch[N][2;
//请同学们不要盲目复制,这里并不是博主设坎,而是只要加上]就没有高亮代码了!
int get(int x){return ch[f[x]][1]==x;}
void updata(int now){size[now]=1+size[ch[now][0]]+size[ch[now][1]];}
void pushdown(int now)
{
    if (deltaz[now])
    {
        swap(ch[now][0],ch[now][1]);
        deltaz[ch[now][0]]^=1; deltaz[ch[now][1]]^=1;
        deltaz[now]=0;
    }
}
bool Is_root(int x){return ch[f[x]][0]!=x && ch[f[x]][1]!=x;}
void rotate(int x)
{
    int old=f[x],oldf=f[old],which=get(x);bool gen=Is_root(old);
    ch[old][which]=ch[x][which^1]; f[ch[x][which^1]]=old;
    ch[x][which^1]=old; f[old]=x;
    f[x]=oldf; if (!gen) ch[oldf][ch[oldf][1]==old]=x;//一定要提前判断gen,如果在这里判断的话f[old]已经转变
    updata(old);
    updata(x);
}
void splay(int x)
{
    int top=0,i;
    for (i=x;!Is_root(i);i=f[i]) stack[++top]=i; 
    stack[++top]=i;
    for (i=top;i>=1;i--) pushdown(stack[i]);

    for (;!Is_root(x);rotate(x))
      if (!Is_root(f[x])) rotate(get(f[x])==get(x)?f[x]:x);
}
void access(int x)
{
    int t=0;
    for (;x;t=x,x=f[x])
    {
        splay(x);
        ch[x][1]=t;
    }
}
void reverse(int x)
{
    access(x);
    splay(x);
    deltaz[x]^=1;
}
void Link(int x,int y)
{
    reverse(x);
    f[x]=y;
    splay(x);
}
void Cut(int x,int y)
{
    reverse(x); access(y);
    splay(y);
    ch[y][0]=f[x]=0;
}
int qurry(int x)
{
    reverse(n+1);
    access(x);
    splay(x);
    return size[ch[x][0]];
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        if (x+i<=n) a[i]=x+i;else a[i]=n+1;
        f[i]=a[i];
        size[i]=1; 
    }
    size[n+1]=1;
    int m;
    scanf("%d",&m);
    while(m--)
    {
        int id,x,v;
        scanf("%d",&id);
        if (id==1)
        {
            scanf("%d",&x);
            x++; printf("%d\n",qurry(x));
        }
        else 
        {
            scanf("%d%d",&x,&v);
            x++;
            Cut(x,a[x]);
            if (x+v<=n) a[x]=x+v;
            else a[x]=n+1;
            Link(x,a[x]);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值