bzoj2002 [Hnoi2010]Bounce 弹飞绵羊 (分块)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Kirito_Acmer/article/details/51945549
Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 7896  Solved: 4124
[Submit][Status][Discuss]

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


思路:这题可以用分块做,先分成sqrt(n)块,然后每一块记录左端点和右端点,然后对于每一个位置维护它跳到下一块或者直接跳到下几块的最小步数以及它跳到下一块的位置,然后询问的时候模拟一下就行了,修改的时候只要把这个位置所属的块的左端点到该点的信息修改下就行了。

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
#define lson th<<1
#define rson th<<1|1
typedef long long ll;
typedef long double ldb;
#define inf 99999999
#define pi acos(-1.0)
#define Key_value ch[ch[root][1]][0]
#define maxn 200050
int k[maxn];
int st[maxn],pt[maxn];  //st表示跳到下一个块要跳的步数,pt表示跳到下一个块或者再下一个块的位置
int l[maxn],r[maxn],belong[maxn];

int n;
int cal(int x)
{
    int i,j;
    int num=0;
    while(x<=n){
        num+=st[x];
        x=pt[x];
    }
    return num;
}


int main()
{
    int m,i,j,f,c,d;
    while(scanf("%d",&n)!=EOF)
    {
        int len=sqrt(n);
        int num=n/len;
        if(n%len)num++;

        for(i=1;i<=num;i++){
            l[i]=(i-1)*len+1;
            r[i]=i*len;
        }
        r[num]=n;

        for(i=1;i<=n;i++){
            belong[i]=(i-1)/len+1;
        }

        for(i=1;i<=n;i++){
            scanf("%d",&k[i]);
        }

        for(i=n;i>=1;i--){
            if(i+k[i]>n){
                st[i]=1;pt[i]=n+1;
            }
            else if(belong[i]==belong[i+k[i] ]  ){
                st[i]=1+st[i+k[i] ];pt[i]=pt[i+k[i] ];
            }
            else{
                st[i]=1;pt[i]=i+k[i];
            }

        }


        scanf("%d",&m);
        for(i=1;i<=m;i++){
            scanf("%d",&f);
            if(f==1){
                scanf("%d",&c);
                c++;
                printf("%d\n",cal(c));
            }
            else if(f==2){
                scanf("%d%d",&c,&d);
                c++;
                k[c]=d;
                for(j=c;j>=l[belong[c] ];j--){
                    if(j+k[j] >n){
                        st[j]=1;pt[j]=n+1;
                    }
                    else if(belong[j]==belong[j+k[j] ]){
                        st[j]=1+st[j+k[j] ];pt[j]=pt[j+k[j] ];
                    }
                    else{
                        st[j]=1;pt[j]=j+k[j];
                    }
                }
            }
        }
    }
    return 0;
}


没有更多推荐了,返回首页