BZOJ2002(分块)
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
分块
1 //2016.8.12 2 #include<iostream> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 7 using namespace std; 8 9 const int N = 200005; 10 int k[N], step[N], nex[N];//step[i]记录i点走出块的步数,nex[i]记录i走出块到达的点 11 12 int main() 13 { 14 int n, m, a, b, c, cnt, ans; 15 scanf("%d", &n); 16 { 17 int len = (int)sqrt(n); 18 for(int i = 0; i < n; i++) 19 scanf("%d", &k[i]); 20 for(int i = n-1; i>0; i--) 21 { 22 int tmp = i+k[i]; 23 if(tmp>=n) 24 { 25 step[i] = 1; 26 nex[i] = -1;//用-1表示走出整个区间 27 }else if(tmp>=(i/len+1)*len) 28 step[i] = 1, nex[i] = tmp; 29 else 30 nex[i] = nex[tmp] , step[i] = step[tmp]+1; 31 } 32 scanf("%d", &m); 33 while(m--) 34 { 35 scanf("%d%d", &a, &b); 36 if(a==1) 37 { 38 ans = 0; 39 for(int i = b; ~i;i = nex[i])//当i==-1时,~i==0,为假退出 40 { 41 ans+=step[i]; 42 } 43 printf("%d\n", ans); 44 }else 45 { 46 scanf("%d", &c); 47 k[b] = c; 48 for(int i = b; i >= b/len*len; i--) 49 { 50 int tmp = i+k[i]; 51 if(tmp>=n) 52 step[i] = 1, nex[i] = -1; 53 else if(tmp>=(i/len+1)*len) 54 step[i] = 1, nex[i] = tmp; 55 else 56 step[i] = step[tmp]+1, nex[i] = nex[tmp]; 57 } 58 } 59 } 60 } 61 62 return 0; 63 }