题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2002

思路

分块,维护块内一个点在块中跳的步数以及出了这个块后去了哪个点。
暴力维护时,注意要用后面节点跳到的位置,来优化寻找前面节点跳到的位置的过程。

代码

#include <cstdio>
#include <cmath>
#include <algorithm>

const int maxn=200000;

int belong[maxn+10],cnt[maxn+10],to[maxn+10],n,m,ki[maxn+10],size;

int main()
{
  scanf("%d",&n);
  for(register int i=0; i<n; ++i)
    {
      scanf("%d",&ki[i]);
    }
  size=(int)sqrt(n);
  for(register int i=0; i<n; ++i)
    {
      belong[i]=i/size+1;
    }
  for(register int i=n-1; i>=0; --i)
    {
      if(i+ki[i]>=n)
        {
          to[i]=-1;
          cnt[i]=1;
        }
      else if(belong[i+ki[i]]!=belong[i])
        {
          to[i]=i+ki[i];
          cnt[i]=1;
        }
      else
        {
          to[i]=to[i+ki[i]];
          cnt[i]=cnt[i+ki[i]]+1;
        }
    }
  scanf("%d",&m);
  while(m--)
    {
      int op,a,b;
      scanf("%d",&op);
      if(op==1)
        {
          scanf("%d",&a);
          int ans=0;
          while(a!=-1)
            {
              ans+=cnt[a];
              a=to[a];
            }
          printf("%d\n",ans);
        }
      else
        {
          scanf("%d%d",&a,&b);
          ki[a]=b;
          for(register int i=a; i>=(belong[a]-1)*size; --i)
            {
              if(i+ki[i]>=n)
                {
                  to[i]=-1;
                  cnt[i]=1;
                }
              else if(belong[i+ki[i]]!=belong[i])
                {
                  to[i]=i+ki[i];
                  cnt[i]=1;
                }
              else
                {
                  to[i]=to[i+ki[i]];
                  cnt[i]=cnt[i+ki[i]]+1;
                }
            }
        }
    }
  return 0;
}