弹飞绵羊——好惨一只羊

弹飞绵羊——好惨一只羊

2022-03-12 18:56:54

thumb_up 1


LCT板子题

构建n+1个节点, 第n+1个表示被弹出

修改即为 link和cut同时使用

本人犯了一个极为无语的错误——主程序修改结点的时候value数组别忘了改

上代码

#include<bits/stdc++.h>
#define MAXN 200010

using namespace std;

int n,m;
int g_v[MAXN],sz[MAXN],ch[MAXN][2],fa[MAXN],flag[MAXN];
//g_v: value array, sz: size of tree, ch: child (left and right), 
//fa: father,
//flag: lazy_tag

bool get(int x)
{
    return (ch[fa[x]][1]==x);
}

bool isroot(int x)//judge whether node x is a root of a splay
{
    return (ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x);
    //认父不认子(dunno how to express in english jeese
}

void pushdown(int rt)
{//tag herediting
    if(!rt||!flag[rt]) 
        return;
    if(ch[rt][0])//left child exists
        flag[ch[rt][0]]^=1;
    if(ch[rt][1])//right child exists
        flag[ch[rt][1]]^=1;
    flag[rt]^=1;
    swap(ch[rt][0],ch[rt][1]);//exchange position of sons(left and right)
}

void push_up(int x)
{
    sz[x]=1;
    if(ch[x][0])
        sz[x]+=sz[ch[x][0]];
    if(ch[x][1])
        sz[x]+=sz[ch[x][1]];
    //recalculate size of subtrees
}

void turn(int x)
{
    int y=fa[x],z=fa[y],k=get(x);
    //y:father, z: grandfather
    if(z&&!isroot(y)){//judge whether it's a root
        if(ch[z][0]==y)ch[z][0]=x;
        else ch[z][1]=x;
        //树旋转(tree spinning???
    }
    ch[y][k]=ch[x][!k]; fa[ch[x][!k]]=y;
    ch[x][!k]=y; fa[y]=x;
    fa[x]=z;
    //reset father and son
    push_up(y);
    push_up(x);
    //reset size
}

void splay(int rt)
{
    int top=0,stack[MAXN];//use stack to store all the roots involved
    stack[++top]=rt;//the first root
    for(int i=rt;!isroot(i);i=fa[i])
        stack[++top]=fa[i];//use function isroot()
    while(top)pushdown(stack[top--]);//passing down tags
    while(!isroot(rt)){
        int x=fa[rt],y=fa[x];
        if(!isroot(x)){
            if((ch[x][0]==rt)^(ch[y][0]==x))turn(rt);
            else turn(x);
            //判断是一字型还是之字形进行different spinning
        }
        turn(rt);//for efficiency
    }
    push_up(rt);
}
void access(int x)
{
    for(int y=0;x;y=x,x=fa[x])
    {
        splay(x);
        ch[x][1]=y;
        push_up(x);
    }
}

void makeroot(int x)
{
    access(x);
    splay(x);
    flag[x]^=1;
}

void split(int x, int y)
{
    makeroot(x);
    access(y);
    splay(y);
}

void cut(int x, int y)
{
    split(x,y);
    fa[x]=0;
    ch[y][0]=0;
    push_up(y);
}

void link(int x, int y)
{
    makeroot(x);
    fa[x]=y;
}

int main()
{

    scanf("%d",&n);
    for(int i=1;i<=n+1;++i)
        sz[i]=1;
    int a,b,c;
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&a);
        g_v[i]=a;
        if(i+a<=n)
            link(i,i+a);
        else
            link(i,n+1);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;++i)
    {
        scanf("%d %d",&a,&b);
        b++;
        if(a==1)
        {
            makeroot(b);
            access(n+1);
            splay(n+1);
            printf("%d\n",sz[n+1]-1);
        }
        else if(a==2)
        {
            scanf("%d",&c);
            //if exceeds n, it means the sheep is bounced into the sky(hahaha
            if(b+g_v[b]>n)
                cut(b,n+1),g_v[b]=c;// reset the valueeeeee
            else
                cut(b,b+g_v[b]),g_v[b]=c;
            if(b+c>n)//similar
                link(b,n+1);
            else
                link(b,b+c);
        }
    }
    return 0;
}
//good luck~
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值