首页 > 代码库 > [HNOI2010]BOUNCE 弹飞绵羊

[HNOI2010]BOUNCE 弹飞绵羊

题目描述

某天,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的情况,你都要输出一个需要的步数,占一行。

 

输入输出样例

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

解题思路

分块经典例题,把这个长度为n的序列分成√n个,对于每段小区间,我们维护以下这几个值:

s[i]---从第i个点跳出该小区间需要的步数(step)

t[i]---跳出该小区间后会到达哪个节点(to)

查询时每次直接 step+=s[i],i=[i],复杂度不超过√n;

修改时直接赋值后把当前块暴力重建,复杂度为√n;

总时间复杂度O(m*√n) 

总空间复杂度O(n)

分点信息(鼠标移到方块上有详细信息)

#1 AC 5ms/14937kB
#2 AC 284ms/14937kB
#3 AC 5ms/14937kB
#4 AC 265ms/14937kB
#5 AC 188ms/14937kB
#6 AC 274ms/14937kB
#7 AC 158ms/14937kB
#8 AC 292ms/14937kB
#9 AC 441ms/14937kB
#10AC448ms/14937kB
 

源代码

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <algorithm>
 5 #define LL long long
 6 using namespace std;
 7 const int N=200200;
 8 int k[N],bl[N],t[N],s[N]; 
 9 int blo,n,m,tot;
10 int read(){
11     int v=0,f=1;char c=getchar();
12     while(c>9||c<0){if(c==-)f*=-1;c=getchar();}
13     while(c<=9&&c>=0)v=v*10+c-0,c=getchar();
14     return v*f;
15 }
16 void reset(int x){
17     for(int i=min(n,x*blo);i>=(x-1)*blo+1;i--){
18         int to=i+k[i];
19         if(to>min(n,x*blo))s[i]=1,t[i]=to;
20         else {
21             s[i]=s[to]+1;
22             t[i]=t[to];
23         }
24     }
25 }
26 int query(int x){
27     int rtn=0;
28     while(x<=n){
29         rtn+=s[x];
30         x=t[x];    
31     }
32     return rtn;
33 }
34 void change(int x,int v){
35     k[x]=v;
36     reset(bl[x]);
37 }
38 int main(){
39     n=read();blo=sqrt(n);
40     for(int i=1;i<=n;i++){
41         k[i]=read();
42         bl[i]=(i-1)/blo+1;
43     }    44     tot=bl[n];
45     for(int i=1;i<=tot;i++)reset(i);
46     m=read();
47     while(m--){
48         int opt,p,v;
49         opt=read();
50         if(opt==1){
51             p=read();
52             printf("%d\n",query(p+1));
53         }
54         if(opt==2){
55             p=read();v=read();
56             change(p+1,v);
57         }
58     }
59     return 0;
60 } 

 

[HNOI2010]BOUNCE 弹飞绵羊