某天,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
非常巧妙的分块 st记录的是 每个点跳到的下一个块的步数。所以更新的时候,如果要跳到的点是同一个块里面的,st更新为到下一个块的点数,而且这个是往后跳 所以从后往前更新即可。然后更新的复杂度就是 sqrt(n),查询的时候最多只会累加sqrt个块,所以复杂度也是sqrt(n)。所以总复杂度就是nsqrt(n)。
#include <bits/stdc++.h>
using namespace std;
const int maxn=2*1e5+10;
int belong[maxn];
int k[maxn];
int nx[maxn];
int l[maxn],r[maxn];
int st[maxn];
int solve(int x){
int ans=0;
while(1){
ans+=st[x];
if(!nx[x]) return ans;
x=nx[x];
}
}
int main()
{
int n;
scanf("%d",&n);
int block=sqrt(n);
int cnt=0;
if(n%block) cnt=n/block+1;
else cnt=n/block;
for(int i=1;i<=n;i++)
scanf("%d",&k[i]);
for(int i=1;i<=cnt;i++)
{
l[i]=(i-1)*block+1,r[i]=i*block;
}
r[cnt]=n;
for(int i=1;i<=n;i++)
belong[i]=(i-1)/block+1;
for(int i=n;i>=1;i--)
{
if(i+k[i]>n) st[i]=1;
else if(belong[i]==belong[i+k[i]])
{
st[i]=st[i+k[i]]+1;
nx[i]=nx[i+k[i]];
}
else
{
st[i]=1;
nx[i]=i+k[i];
}
}
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int a,b,c;
scanf("%d%d",&a,&b);
b++;
if(a==1)
{
printf("%d\n",solve(b) );
}
else{
scanf("%d",&c);
k[b]=c;
for(int j=b;j>=l[belong[b]];j--)
{
if(j+k[j]>n) st[j]=1,nx[j]=0;
else if(belong[j]==belong[j+k[j]])
{
st[j]=st[j+k[j]]+1;
nx[j]=nx[j+k[j]];
}
else
{
st[j]=1;
nx[j]=j+k[j];
}
}
}
}
}