首先我们可以将序列分成根号n块,对于每个装置处理出它弹到下一块时的次数,这样通过n根号n的预处理,就可以实现根号n的查询。对于每个修改操作,我们只需对于修改的这一块进行暴力维护,复杂度也是根号n,这样我们就能用n根号n的时间解决这道题。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 200005
#define block 447
int c[maxn],a[maxn],n,m,q;
int block_cnt,b[maxn],d[maxn],l[500],r[500];
int query(int k)
{
int ans=0;
while (1)
{
ans+=d[k];
if (c[k]==n+1) return ans;
k=c[k];
}
}
void change(int k,int z)
{
a[k]=z;
for (int i=r[b[k]];i>=l[b[k]];i--)
{
int j=a[i]+i;
if (j>n) {c[i]=n+1;d[i]=1;}
else if (b[j]!=b[i]) {c[i]=j;d[i]=1;}
else {c[i]=c[j];d[i]=d[j]+1;}
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",a+i);
for (int i=1;i<=n;i++)
{
b[i]=(i-1)/block+1;
if (b[i]!=b[i-1])
{
l[b[i]]=i;
r[b[i-1]]=i-1;
}
}
block_cnt=(n-1)/block+1;
r[block_cnt]=n;
for (int i=n;i>=1;i--)
{
int j=i+a[i];
if (j>n) {c[i]=n+1;d[i]=1;}
else if (b[j]!=b[i]) {c[i]=j;d[i]=1;}
else {c[i]=c[j];d[i]=d[j]+1;}
}
// for (int i=1;i<=n;i++)
// printf("%d %d\n",c[i],d[i]);
scanf("%d",&q);
for (int i=1;i<=q;i++)
{
int x,y,z;
scanf("%d%d",&x,&y);
y++;
if (x==1) printf("%d\n",query(y));
else
{
scanf("%d",&z);
change(y,z);
}
}
return 0;
}