BZOJ2002:Bounce 弹飞绵羊(LCT)

 

之前用分块解过这道题,不过最近学到了LCT,发现它也是LCT的模板题,就用LCT做了一下。

分块解法:https://blog.csdn.net/f2935552941/article/details/78157052

 

LCT的话,推荐一篇博客,讲的比较清楚,但是如果想深入了解的话建议可以找国家集训队的论文看一下。

推荐博客:https://blog.csdn.net/JeremyGJY/article/details/51078087

 

解题思路:

这道题目具体就是我们对于 x 和 x+a[x] 建立一条边,如果 x+a[x] 大于 n,就默认建到 n+1 即可,之后查询 x 跳出次数,就是把 x 到 n+1 的链挑出来,这条链上的结点数-1 即可。

修改的话就用正常的删边和建边实现即可,

发现了大佬的一个板子,感觉还挺不错的。

 

Ac代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int mod=1e9+7;
const int INF=1e9+7;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
int n,m,a[maxn];
struct LCT  //LCT模板
{
    int father[maxn+5],son[maxn+5][2],si[maxn+5];
    bool flip[maxn+5];
    void init(){ for(int i=1;i<=n+1;i++) si[i]=1; }
    void Pushup(int p) {si[p]=si[son[p][0]]+1+si[son[p][1]];}
    void Add_flip(int p) {swap(son[p][0],son[p][1]);flip[p]^=1;}
    void Pushdown(int p)
    {
        if (!flip[p]) return;
        if (son[p][0]) Add_flip(son[p][0]);
        if (son[p][1]) Add_flip(son[p][1]);
        flip[p]=false;
    }
    bool is_ro(int p) {return p!=son[father[p]][0]&&p!=son[father[p]][1];}
    void Rotate(int p)
    {
        int fa=father[p],d=p==son[fa][0];
        if (!is_ro(fa)) son[father[fa]][fa==son[father[fa]][1]]=p;
        son[fa][d^1]=son[p][d];father[son[p][d]]=fa;son[p][d]=fa;
        Pushup(fa);Pushup(p);father[p]=father[fa];father[fa]=p;
    }
    int top,stk[maxn+5];
    void Splay(int p)
    {
        stk[++top]=p;
        for (int i=p;!is_ro(i);i=father[i]) stk[++top]=father[i];
        while (top) Pushdown(stk[top--]);
        while (!is_ro(p))
        {
            int fa=father[p];
            if (!is_ro(fa))
            {
                int d1=fa==son[father[fa]][1],d2=p==son[fa][1];
                if (d1==d2) Rotate(fa); else Rotate(p);
            }
            Rotate(p);
        }
    }
    void Access(int p)
    {
        int lst=0;
        while (p)
        {
            Splay(p);son[p][1]=lst;Pushup(p);
            lst=p;p=father[p];
        }
    }
    void make_ro(int p) {Access(p);Splay(p);Add_flip(p);}
    void Link(int x,int y) {Access(y);make_ro(y);father[y]=x;}
    void Cut(int x,int y)
    {
        make_ro(y);Access(x);Splay(x);
        father[y]=son[x][0]=0;Pushup(x);
    }
};
LCT tr;
int main()
{
    scanf("%d",&n); tr.init();  //初始化
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),tr.Link(min(i+a[i],n+1),i);   //建边
    scanf("%d",&m);
    while(m--)
    {
        int flag,x,y;
        scanf("%d",&flag);
        if(flag==1)
        {
            scanf("%d",&x); x++;
            tr.make_ro(n+1);tr.Access(x);tr.Splay(x);
            printf("%d\n",tr.si[x]-1);
        }
        else 
        {
            scanf("%d%d",&x,&y); x++;
            tr.Cut(min(x+a[x],n+1),x),tr.Link(min(x+y,n+1),x);
            a[x]=y;
        }
    }
    //system("pause");
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值