[bzoj2002] [Hnoi2010]Bounce 弹飞绵羊

[Hnoi2010]Bounce 弹飞绵羊

Description

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

Input

第一行包含一个整数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

Output

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

Sample Input

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

Sample Output

2
3

Solution

这题是一道LCT的例题,然而我怎么会LCT呢,于是就有分块大暴力搞定了。

首先高呼:分块大法好!分块大法好!分块大法好!

首先,分块,对于每一个点维护两个东西:跳出这个块需要多少部,以及跳出之后到了哪个点。
预处理O(N),要注意如果你打了 O(nn) 的时间,在BZOJ的慢速评测下就会T
对于询问,最多只会跳 n 次,时间复杂度为 O(n)
对于修改,暴力修改这个块内的点,一个块只有 n 个点,时间复杂度 O(n)
总时间复杂度 O(mn)

(这句是一年以后加的)但是现在我会LCT了,点击这里进入

Code

#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define big 448
int n,a[201000],b[201000],c[201000],ac,be[201000];
int main()
{
    scanf("%d",&n);
    fo(i,1,n) scanf("%d",&a[i]),be[i]=(i-1)/big+1;
    b[n]=n+1;c[n]=0;
    for(int i=n;i;i--) 
    if(be[i]==be[i+a[i]]) c[i]=c[i+a[i]]+1,b[i]=b[i+a[i]];
    else c[i]=1,b[i]=i+a[i];
    for(scanf("%d",&ac);ac;ac--)
    {
        int jy;scanf("%d",&jy);
        if(jy==1)
        {
            int x,ans=0;scanf("%d",&x);x++;
            for(;x<=n;x=b[x]) ans+=c[x];
            printf("%d\n",ans);
        }
        else
        {
            int x,y;scanf("%d%d",&x,&y); 
            int i=++x;c[i]=0;a[i]=y;
            for(;x<=n&&be[x]==be[i];x=x+a[x]) c[i]++;b[i]=x;
            for(int j=i-1;be[j]==be[i]&&j>0;j--) if(be[j+a[j]]==be[i]) c[j]=c[j+a[j]]+1,b[j]=b[j+a[j]];
        }
    }
}

另外吐槽

我恨BZOJ不能下载错误的点

你可能感兴趣的:(题解,暴力,分块)