【codevs2333】弹飞绵羊

原本这个题的正解是lct,可是自从这个题被人发现可以用分块做,然后就成为了分块的练习题233333,而且虽然lct的时间复杂度是nlogn的,可是因为常数太大,反而跑不过分块,挺有意思的

这个题我们可以设置sqrt(n)个块,然后维护块内每个元素到下一个块的最小步数和到到达下一个块的第一个点,然后这样每次查询、修改的时间复杂度最坏是sqrt(n),所以最后时间复杂度是m√n

PS:这个题的题号也挺有意思的23333333

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int n,m,ne[200020],g,xi[200020],bu[200020],x,y,z;
inline void ask(int x)//询问需要多少步 
{
    int re=0;
    while(1)//一直跳,直到能够跳出n 
    {
        re+=bu[x];
        if(!ne[x])//因为 能直接跳到n的都没赋值 
            break;
        x=ne[x];
    }
    printf("%d\n",re);
}
inline void cha(int wei,int zhi)//进行修改 
{
    xi[wei]=zhi;//先改完装置的弹力系数 
    for(int i=wei;i>=(((wei-1)/g+1)-1)*g+1;i--)//所有关于这个块的信息都要更新 
    {
        if((i+xi[i]-1)/g+1==(i-1)/g+1)//如刚才的初始化 
            bu[i]=bu[i+xi[i]]+1,ne[i]=ne[i+xi[i]];
        else
            bu[i]=1,ne[i]=i+xi[i];
    }
}
int main()
{
    scanf("%d",&n);
    g=sqrt(n);
    for(int i=1;i<=n;i++) 
        scanf("%d",&xi[i]);
    for(int i=n;i>0;i--)
    {
        if(i+xi[i]>n)//因为我们输入的是从1到n,相当于整体都加1了,所以大于n 
            bu[i]=1;
        else if((i+xi[i]-1)/g+1==(i-1)/g+1)//如果这两个点位于同一个块,说明从这个弹射装置出发不能直接飞出这个块 
            bu[i]=bu[i+xi[i]]+1,ne[i]=ne[i+xi[i]];//因此它的步数相当于它跳到的下一个块跳出去这个块的步数+1,从它出发跳到块外的第一个点是下个块的答案 
        else
            bu[i]=1,ne[i]=i+xi[i];//否则说明从这个点能够直接跳出这个块 
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        y++;//整体加1 
        if(x==1)
            ask(y);
        else    
            scanf("%d",&z),cha(y,z);
    }
}

 

posted @ 2017-10-30 18:41  那一抹落日的橙  阅读(289)  评论(0编辑  收藏  举报