【bzoj 2002】 Bounce 弹飞绵羊 题解&代码

题目链接:

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--;
            }
        }
    }
}

你可能感兴趣的:(C++,分块,bzoj)