题意
某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。
游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。
绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。
为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
n≤200000
分析
正解LCT。
但是可以考虑分块。
我们将位置分成
⌊n√⌋
块,对于每一块进行维护。
每一块我们需要保存以下几个值:
wij
:第
i
块第
lastij
:第
i
块第
cntij
:第
i
块第
这样可以解决询问操作:
假设从
x
开始跳,首先
现在只用解决维护就可以了。
最初的时候,我们需要求这三个的初始值。
由于每一块的取值不受外界影响,所以我们每一块分开来求,使用函数
Calculate(i)
表示求第
i
块。
从块内的最后一个元素往前递推,分跳到块内、跳到块外处理。
后来的更改,只用暴力找到位置更改了,然后整块用
代码
#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;
}