BZOJ2002[Hnoi2010]弹飞绵羊——LCT

题目描述

某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

输入

第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1,接下来一行有n个正整数,依次为那n个装置的初始弹力系数。第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

输出

对于每个i=1的情况,你都要输出一个需要的步数,占一行。

样例输入

4
1 2 1 1
3
1 1
2 1 1
1 1

样例输出

2
3
 
当跳过n之后就被弹飞,那么可以建一个虚点n+1,将弹飞看作弹到n+1这个节点上。
i会被弹到i+ki号节点上,那么直接将i号节点和i+ki号节点连上就好了。
修改直接断开原来连的边,重新连接一条边,LCT维护就好了。
因为每个点只会连接一个比它编号大的点,所以最后形成了一棵树,每次询问直接查询j和n+1路径上的节点数-1即可。
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int x,y;
int opt;
int s[200020][2];
int f[200020];
int r[200020];
int st[200020];
int size[200020];
int dis[200020];
int get(int rt)
{
    return rt==s[f[rt]][1];
}
void pushup(int rt)
{
    size[rt]=size[s[rt][0]]+size[s[rt][1]]+1;
}
void pushdown(int rt)
{
    if(r[rt])
    {
        r[s[rt][0]]^=1;
        r[s[rt][1]]^=1;
        r[rt]^=1;
        swap(s[rt][0],s[rt][1]);
    }
}
int is_root(int rt)
{
    return rt!=s[f[rt]][0]&&rt!=s[f[rt]][1];
}
void rotate(int rt)
{
    int fa=f[rt];
    int anc=f[fa];
    int k=get(rt);
    if(!is_root(fa))
    {
        s[anc][get(fa)]=rt;
    }
    s[fa][k]=s[rt][k^1];
    f[s[fa][k]]=fa;
    s[rt][k^1]=fa;
    f[fa]=rt;
    f[rt]=anc;
    pushup(fa);
    pushup(rt);
}
void splay(int rt)
{
    int top=0;
    st[++top]=rt;
    for(int i=rt;!is_root(i);i=f[i])
    {
        st[++top]=f[i];
    }
    for(int i=top;i>=1;i--)
    {
        pushdown(st[i]);
    }
    for(int fa;!is_root(rt);rotate(rt))
    {
        if(!is_root(fa=f[rt]))
        {
            rotate(get(fa)==get(rt)?fa:rt);
        }
    }
}
void access(int rt)
{
    for(int x=0;rt;x=rt,rt=f[rt])
    {
        splay(rt);
        s[rt][1]=x;
        pushup(rt);
    }
}
void reverse(int rt)
{
    access(rt);
    splay(rt);
    r[rt]^=1;
}
int find(int rt)
{
    access(rt);
    splay(rt);
    while(s[rt][0])
    {
        rt=s[rt][0];
    }
    return rt;
}
void link(int x,int y)
{
    reverse(x);
    f[x]=y;
}
void cut(int x,int y)
{
    reverse(x);
    access(y);
    splay(y);
    s[y][0]=f[x]=0;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n+1;i++)
    {
        size[i]=1;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        dis[i]=x;
        if(i+x<=n)
        {
            link(i,i+x);
        }
        else
        {
            link(i,n+1);
        }
    }
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d",&x);
            x++;
            reverse(x);
            access(n+1);
            splay(n+1);
            printf("%d\n",size[n+1]-1);
        }
        else
        {
            scanf("%d%d",&x,&y);
            x++;
            if(x+dis[x]<=n)
            {
                cut(x,x+dis[x]);
            }
            else
            {
                cut(x,n+1);
            }
            dis[x]=y;
            if(x+dis[x]<=n)
            {
                link(x,x+dis[x]);
            }
            else
            {
                link(x,n+1);
            }
        }
    }
}
posted @ 2018-10-05 14:35  The_Virtuoso  阅读(255)  评论(0编辑  收藏  举报