某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
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
暴力://数据有漏洞
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m; int num[200010],nxt[200010],step[200010]; void xiugai(int l,int r) { for(int i=r;i>=l;i--) { if(nxt[i]>=n) { step[i]=1; continue; } if(nxt[i]<n&&step[nxt[i]]!=0) { step[i]=step[nxt[i]]+1; continue; } } } int main() { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&num[i]); memset(step,0,sizeof(step)); for(int i=0;i<n;i++) nxt[i]=i+num[i]; xiugai(0,n-1); scanf("%d",&m); int a,b,c; while(m--) { scanf("%d",&a); if(a==1) { scanf("%d",&b); printf("%d\n",step[b]); } else { scanf("%d%d",&b,&c); if(num[b]==c) continue; num[b]=c; nxt[b]=b+num[b]; xiugai(0,b); } } return 0; }
将序列分块,每块sqrt(n)个。
在每个块中维护f[i],to[i]
f[i] 表示跳几次可以跳出所在块
to[i] 表示跳出所在块后到达的位置。
在查询时,我们O(sqrt(n))的时间进行“整块”的模拟,可以得到结果。
在修改i时,我们只需维护一下(l[belong[i]]--i)的序列就可以了。
总复杂度:O(n*sqrt(n))
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <cmath> using namespace std; int f[200005],to[200005],k[200005],bl[200005]; int n,m,tot,l[200005]; void Init() { int i,j; scanf("%d",&n); m=int(sqrt(n)); j=m; for (i=0;i<n;i++) { if (j==m) j=1,tot++,l[tot]=i; else j++; scanf("%d",k+i); bl[i]=tot; } l[tot+1]=n; for (i=n-1;i>=0;i--) if (i+k[i]>=l[bl[i]+1]) f[i]=1,to[i]=i+k[i]; else f[i]=f[i+k[i]]+1,to[i]=to[i+k[i]]; } int ask(int p) { int s=0; while (p<n) {s+=f[p];p=to[p];} return s; } void replace(int p,int k1) { k[p]=k1; int i; for (i=p;i>=l[bl[p]];i--) if (i+k[i]>=l[bl[i]+1]) f[i]=1,to[i]=i+k[i]; else f[i]=f[i+k[i]]+1,to[i]=to[i+k[i]]; } void Work() { int x,y,z; for (scanf("%d",&m);m--;) { scanf("%d",&x); if (x==1) { scanf("%d",&y); printf("%d\n",ask(y)); } else { scanf("%d%d",&y,&z); replace(y,z); } } } int main() { Init(); Work(); return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
BZOJ 2002 Bounce 弹飞绵羊(分块|暴力|)(困难)
原文地址:http://blog.csdn.net/kaisa158/article/details/47264093