題意
某天,Lostmonkey發明了一種超級彈力裝置,爲了在他的綿羊朋友面前顯擺,他邀請小綿羊一起玩個遊戲。
遊戲一開始,Lostmonkey在地上沿着一條直線擺上n個裝置,每個裝置設定初始彈力系數ki,當綿羊達到第i個裝置時,它會往後彈ki步,達到第i+ki個裝置,若不存在第i+ki個裝置,則綿羊被彈飛。
綿羊想知道當它從第i個裝置起步時,被彈幾次後會被彈飛。
爲了使得遊戲更有趣,Lostmonkey可以修改某個彈力裝置的彈力系數,任何時候彈力系數均爲正整數。
分析
正解LCT。
但是可以考慮分塊。
我們將位置分成
每一塊我們需要保存以下幾個值:
這樣可以解決詢問操作:
假設從
現在只用解決維護就可以了。
最初的時候,我們需要求這三個的初始值。
由於每一塊的取值不受外界影響,所以我們每一塊分開來求,使用函數
從塊內的最後一個元素往前遞推,分跳到塊內、跳到塊外處理。
後來的更改,只用暴力找到位置更改了,然後整塊用
代碼
#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;
}