BZOJ 2002 Hnoi2010 弹飞绵羊 分块

来源:互联网 发布:淘宝如何在团购网引流 编辑:程序博客网 时间:2024/05/22 08:22

题意

某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。

游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。

绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。

为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

n200000

分析

正解LCT。
但是可以考虑分块。

我们将位置分成n块,对于每一块进行维护。
每一块我们需要保存以下几个值:
wij:第i块第j个位置能往前跳多少个位置;
lastij:第i块第j个位置在本块跳到的最后位置;
cntij:第i块第j个位置跳到本块最后一个位置需要多少步;

这样可以解决询问操作:
假设从x开始跳,首先xlast跳到块尾,答案累加用cnt,再用w数组将x跳到块尾位置跳到的下一个位置,直到跳出。

现在只用解决维护就可以了。

最初的时候,我们需要求这三个的初始值。
由于每一块的取值不受外界影响,所以我们每一块分开来求,使用函数Calculate(i)表示求第i块。
从块内的最后一个元素往前递推,分跳到块内、跳到块外处理。

后来的更改,只用暴力找到位置更改了,然后整块用Calculate重新求一次。

代码

#include <cstdio>#include <cctype>#include <cmath>#include <algorithm>using namespace std;const int N=200010;const int BLOCK_SIZE=500;const int BLOCK_MAX=500;int n;int unit,tot;int w[BLOCK_SIZE][BLOCK_MAX];int cnt[BLOCK_SIZE][BLOCK_MAX];int last[BLOCK_SIZE][BLOCK_MAX];inline int Read(void){    int x=0,f=1; char c=getchar();    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;    for (;isdigit(c);c=getchar()) x=x*10+c-'0';    return x*f;}void Calculate(int nb){    int bnum=min(unit,n-(nb-1)*unit); int gb,gl;    for (int i=bnum;i>=1;i--)        if (i+w[nb][i]>bnum)        {            cnt[nb][i]=1;            last[nb][i]=i;        }        else        {            cnt[nb][i]=cnt[nb][i+w[nb][i]]+1;            last[nb][i]=last[nb][i+w[nb][i]];        }}void Init(void){    n=Read();       unit=(int)sqrt(n);    int cur=unit;    for (int i=1;i<=n;i++)    {        if (cur==unit) tot++,cur=0;        w[tot][++cur]=min(Read(),n+1);    }    for (int i=1;i<=tot;i++) Calculate(i);}int m;int Query(int x){    int nb,nl,sum=0;    for (;x<=n;)    {        nb=(x-1)/unit+1,nl=x-(nb-1)*unit;        sum+=cnt[nb][nl];        x=(nb-1)*unit+last[nb][nl]+w[nb][last[nb][nl]];    }    return sum;}void Update(int x,int y){    int nb=(x-1)/unit+1,nl=x-(nb-1)*unit;    w[nb][nl]=y;    Calculate(nb);}void Work(void){    int k,x,y; m=Read();    for (int i=1;i<=m;i++)    {        k=Read();        if (k==1)        {            x=Read()+1;            printf("%d\n",Query(x));        }        else        {            x=Read()+1,y=Read();            Update(x,y);        }    }}int main(void){    Init();    Work();    return 0;}
0 0
原创粉丝点击