解题思路:
我们可以在分块后维护每个位置弹出该块所需步数和弹到的位置,这样查询和修改都是 O(n√) 的了。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<queue>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=200005;
int n,m,S,cnt;
int k[N],st[N],pt[N],id[N],l[N];
int calc(int x)
{
int res=0;
for(;x;x=pt[x])res+=st[x];
return res;
}
void modify(int x)
{
k[x]=getint();
for(int i=x;i>=l[id[x]];i--)
{
if(i+k[i]>n)st[i]=1,pt[i]=0;
else if(id[i]!=id[i+k[i]])st[i]=1,pt[i]=i+k[i];
else st[i]=st[i+k[i]]+1,pt[i]=pt[i+k[i]];
}
}
int main()
{
//freopen("lx.in","r",stdin);
n=getint();S=sqrt(n);
for(int i=1;i<=n;i++)k[i]=getint();
if(n%S)cnt=n/S+1;
else cnt=n/S;
for(int i=1;i<=cnt;i++)l[i]=(i-1)*S+1;
for(int i=1;i<=n;i++)id[i]=(i-1)/S+1;
for(int i=n;i;i--)
{
if(i+k[i]>n)st[i]=1;
else if(id[i]!=id[i+k[i]])st[i]=1,pt[i]=i+k[i];
else st[i]=st[i+k[i]]+1,pt[i]=pt[i+k[i]];
}
m=getint();
while(m--)
{
int op=getint(),x=getint()+1;
if(op==1)cout<<calc(x)<<'\n';
else modify(x);
}
return 0;
}