时间限制:1 s
内存限制:259 MB
【题目描述】
某天,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。对于10%的数据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
由于修改操作很多,可以将复杂度摊给询问操作。
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <cmath>
5 using namespace std;
6 const int maxn=200010;
7 int a[maxn],bel[maxn],sum[maxn],to[maxn];
8 int n,m,K,Q;
9 int Query(int x){
10 int ret=0;
11 while(x!=-1){
12 ret+=sum[x];
13 x=to[x];
14 }
15 return ret;
16 }
17 int main(){
18 freopen("bzoj_2002.in","r",stdin);
19 freopen("bzoj_2002.out","w",stdout);
20 scanf("%d",&n);
21 m=sqrt(n+0.5);
22 for(int i=1;i<=n;i++){
23 if((i-1)%m==0)K++;
24 bel[i]=K;
25 scanf("%d",&a[i]);
26 }
27 for(int i=n;i>=1;i--){
28 if(i+a[i]>n){
29 to[i]=-1;
30 sum[i]=1;
31 }
32 else{
33 if(bel[i]==bel[i+a[i]]){
34 to[i]=to[i+a[i]];
35 sum[i]=sum[i+a[i]]+1;
36 }
37 else{
38 to[i]=i+a[i];
39 sum[i]=1;
40 }
41 }
42 }
43 scanf("%d",&Q);
44 while(Q--){
45 int op,x,y;
46 scanf("%d",&op);
47 if(op==1){
48 scanf("%d",&x);x++;
49 printf("%d
",Query(x));
50 }
51 else{
52 scanf("%d%d",&x,&y);x++;
53 a[x]=y;
54 if(x+y>n){
55 sum[x]=1;
56 to[x]=-1;
57 }
58 else{
59 if(bel[x]==bel[x+y]){
60 to[x]=to[x+y];
61 sum[x]=sum[x+y]+1;
62 }
63 else{
64 to[x]=x+y;
65 sum[x]=1;
66 }
67 }
68 for(int p=x-1;bel[p]==bel[x];p--)
69 if(bel[p]==bel[p+a[p]])
70 sum[p]=sum[p+a[p]]+1,to[p]=to[p+a[p]];
71 }
72 }
73 return 0;
74 }