P3203 [HNOI2010]弹飞绵羊

题目描述

某天,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。

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 复制
4
1 2 1 1
3
1 1
2 1 1
1 1
输出样例#1: 复制
2
3

说明

对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=2e5+5;

inline int read()
{
    char c=getchar();int num=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
        num=num*10+c-'0';
    return num; 
}

int f[N],c[N][2],s[N]; 

inline bool nroot(int x)
{
    return c[f[x]][0]==x||c[f[x]][1]==x;
}

inline void pushup(int x)
{
    s[x]=s[c[x][0]]+s[c[x][1]]+1;
}

inline void rotate(int x)
{
    int y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
    if(nroot(y))
        c[z][c[z][1]==y]=x;
    c[x][!k]=y,c[y][k]=w;
    if(w)
        f[w]=y;
    f[y]=x,f[x]=z;
    pushup(y);
}

inline void splay(int x)
{
    int y,z;
    while(nroot(x))
    {
        y=f[x],z=f[y];
        if(nroot(y))
            rotate((c[y][0]==x)^(c[z][0]==y)?y:x);
        rotate(x);
    }
    pushup(x);
}

inline void access(int x)
{
    for(int y=0;x;x=f[y=x])
        splay(x),c[x][1]=y,pushup(x);
}

int opt;
int n,m,j,k;
int main()
{
//    freopen("testdata.in","r",stdin);
//    freopen("233.out","w",stdout);
    n=read();
    for(int i=1;i<=n;++i)
    {
        s[i]=1;
        k=read();
        if(i+k<=n)
            f[i]=i+k;    //没有被弹飞,连边 
    }
    m=read();
    while(m--)
    {
        opt=read();
        if(opt&1)
        {
            j=read(),++j;
            access(j),splay(j);    //将j与根打通,然后让j为根,直接查询
            printf("%d\n",s[j]); 
        }
        else
        {
            j=read(),k=read(),++j;
            access(j),splay(j);
            c[j][0]=f[c[j][0]]=0;    //断边
            if(j+k<=n)
                f[j]=j+k;    //连边
            pushup(j);
        }
    }
    return 0;
}

 

posted @ 2018-09-12 11:37  whymhe  阅读(215)  评论(0编辑  收藏  举报