BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊(分块)
2002: [Hnoi2010]Bounce 弹飞绵羊
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 14563 Solved: 7382
[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
1 2 1 1
3
1 1
2 1 1
1 1
Sample Output
2
3
题解
一个题外话分块似乎是正解
(下面的是LCT,上面的是分块)(码的少,跑的快)
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<cstdio> 5 #include<algorithm> 6 using namespace std; 7 const int N=200010; 8 int n,Block,a[N],m,block[N],r[200],f[N],to[N]; 9 int main(){ 10 scanf("%d",&n);Block=sqrt(n); 11 for(int i=1;i<=n;i++){ 12 scanf("%d",&a[i]); 13 block[i]=(i-1)/Block+1; 14 } 15 for(int i=1;i<=block[n];i++){ 16 if(i==block[n])r[i]=n; 17 else r[i]=r[i-1]+Block; 18 } 19 block[n+1]=block[n]+1; 20 for(int i=n;i>=1;i--){ 21 if(i+a[i]>n){f[i]=1;to[i]=n+1;continue;} 22 if(i+a[i]>r[block[i]]){f[i]=1;to[i]=i+a[i];} 23 else {f[i]=f[i+a[i]]+1;to[i]=to[i+a[i]];} 24 } 25 scanf("%d",&m); 26 for(int i=1;i<=m;i++){ 27 int k; 28 scanf("%d",&k); 29 if(k==1){ 30 int x;int ans=0; 31 scanf("%d",&x);x++; 32 while(x!=n+1){ans+=f[x];x=to[x];} 33 printf("%d\n",ans); 34 } 35 else{ 36 int x,y; 37 scanf("%d%d",&x,&y);x++; 38 a[x]=y; 39 for(int j=x;j>=r[block[x]-1]+1;j--){ 40 if(j+a[j]>n){f[j]=1;to[j]=n+1;} 41 else if(j+a[j]>r[block[j]]){f[j]=1;to[j]=j+a[j];} 42 else {f[j]=f[j+a[j]]+1;to[j]=to[j+a[j]];} 43 } 44 } 45 } 46 return 0; 47 }