BZOJ 2002 Bounce 弹飞绵羊(分块|暴力|)(困难)

来源:互联网 发布:淘宝被永久封能解开吗 编辑:程序博客网 时间:2024/04/27 23:14

Bounce 弹飞绵羊

Time Limit:10000MS     Memory Limit:265216KB     64bit IO Format:%lld & %llu
Submit Status Practice HYSBZ 2002

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 31 12 1 11 1

Sample Output

23

暴力://数据有漏洞

#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;}




0 0
原创粉丝点击