题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=2002
题解:
第一道分块类题,首先将整个序列分块(一般都是分为根号n块,这样的话每块长度大概都是根号n),记录每个点通过不断的跳跃之后需要几步能跳出自己所在的块儿,并且记录这个点跳出自己所在的块儿之后会跳在哪个点,这样的话,查询用while循环,一直循环到跳出这个序列,并沿途记录步数,复杂度最坏为 根号n,因为只有 根号n 块,每次修改一个点的k值,只需要更改自己块儿内会跳到自己的点,因为其他块儿内的点到这个块的步数都是后来while循环记录的,不会受到修改的影响。
代码:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<math.h>
#define maxn (200005)
#define maxm (100005)
using namespace std;
int ans,x,y,z,d,num,n,m,k[maxn],sq[maxn],p[maxn],nex[maxn],st[maxn];
int main()
{
scanf("%d",&n);
d=sqrt(n);
for (int i=1;i<=n;i++)
{
scanf("%d",&k[i]);
sq[i]=i/d+1;
}
for (int i=n;i>=1;i--)
{
int tmp=i+k[i];
if (tmp>n)
{nex[i]=-1;p[i]=1;continue;}
else if (sq[tmp]!=sq[i])
nex[i]=tmp,p[i]=1;
else
nex[i]=nex[tmp],p[i]=p[tmp]+1;
}
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
scanf("%d",&z);
if (z==1)
{
scanf("%d",&x);
x++;ans=0;
while(x!=-1)
{
ans+=p[x];
x=nex[x];
}
printf("%d\n",ans);
}
else
{
scanf("%d%d",&x,&y);
x++;k[x]=y;
int tmp=x+k[x];
if (tmp>n) nex[x]=-1,p[x]=1;
else if (sq[tmp]!=sq[x]) p[x]=1,nex[x]=tmp;
else p[x]=p[tmp]+1,nex[x]=nex[tmp];
int j=x-1;
while(sq[j]==sq[x])
{
int tmp=j+k[j];
if (sq[tmp]==sq[j])
p[j]=p[tmp]+1,nex[j]=nex[tmp];
j--;
}
}
}
}