BZOJ2002 HNOI2010 Bounce 弹飞绵羊 题解&代码

这几天一直在bzoj水不能见人的水题…有时间补补题解吧【说得好像这题不水一样
很简单的分块!
第一次写到这么简单的分块!
整个人都舒爽了!
虽然还是WA了两次…妈的我只是写完一激动忘了输出后加回车…

将整个长区间分成近似于sqrt(n)块【分块方法随意,满足可逆性即可
对于每一块,处理出块内每个点弹出这一块所需步数
然后每次查询最多累计sqrt(n)次(块数次)
每次修改最多修改sqrt(n)次(块大小次)
完美【呸

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 200005;
int n,m,len,c,x,y,k[maxn],block[maxn],next[maxn],step[maxn];
void f(int p,int i)
{
    if(p>=n)step[i] = 1, next[i]=-1;
        else if(block[p]!=block[i]) step[i]=1,next[i]=p;
                else step[i] = step[p]+1, next[i]=next[p];

}
void cal(void)
{
    for(int i = n-1; i >= 0; i--)
        f(i+k[i],i);
}
int query(int x,int ret)
{
    ret+=step[x];
    if(next[x]==-1)return ret;
    return query(next[x],ret);
}
void change(int x,int y)
{
    if(k[x]==y)return;
    k[x]=y;
    int temp =(block[x]-1)*len;
    for(int i = x; i >= temp; i--)
        f(i+k[i],i);
}
int main (void)
{
    scanf("%d",&n);
    len = sqrt(n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d",&k[i]);
        block[i]=i/len+1;
    }
    cal();
    scanf("%d",&m);
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d",&c,&x);
        if(c==1)printf("%d\n",query(x,0));
        else
        {
            scanf("%d",&y);
            change(x,y);
        }
    }
    return 0;
}

你可能感兴趣的:(BZOJ2002 HNOI2010 Bounce 弹飞绵羊 题解&代码)