BZOJ P2002 [HNOI2010] 弹飞绵羊【分块】

这道题就很优秀了。考试的时候完全没想到正解,最后写了一个暴力20分……

直接讲分块吧。我们预处理两个数组 S t e p [ ] , G e t [ ] ,其中 S t e p [ i ] 表示第 i 个数跳到下一块需要的步数, G e t [ I ] 表示第 i 个数跳到下一块中的哪一个数,这样我们就只需要分块处理就可以了。

再讲一下预处理与查询与修改吧。

关于预处理:我们从后往前扫,判断一下当前的这个数与这个数直接跳的数是否处于同一个块中,如果是的话就直接 S t e p [ x ] = S t e p [ x + J u m p [ x ] ] + 1 G e t [ x ] = G e t [ x + J u m p [ x ] ] ,不然的话就 S t e p [ x ] = 1 G e t [ x ] = x + J u m p [ x ] 。时间复杂度: O ( n )

关于查询:我们从起点 x 开始,先将步数记录 A n s + = S t e p [ x ] ,然后再跳过去 x = G e t [ x ] ,就这样循环一直到 G e t [ x ] = 0 。时间复杂度: n

关于修改:修改的话就最开始 J u m p [ x ] = y ,然后我们循环 f o r ( i = x ; i >= L e f t [ B l o c k [ x ] ] ; i ) 预处理操作了。时间复杂度: n

总时间复杂度: O ( n + m n )

参考代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define DB double
#define SG string
#define LL long long
using namespace std;
const LL Max=2e5+5;
const LL Mod=1e9+7;
const LL Inf=1e18;
LL N,M,S,SNum,L[Max],R[Max],Get[Max],Step[Max],Jump[Max],Block[Max];
inline LL Read(){
    LL X=0;char CH=getchar();bool F=0;
    while(CH>'9'||CH<'0'){if(CH=='-')F=1;CH=getchar();}
    while(CH>='0'&&CH<='9'){X=(X<<1)+(X<<3)+CH-'0';CH=getchar();}
    return F?-X:X;
}
inline void Write(LL X){
    if(X<0)X=-X,putchar('-');
    if(X>9)Write(X/10);
    putchar(X%10+48);
}
void Update(LL X,LL Y){
    LL I;Jump[X]=Y;
    for(I=X;I>=L[Block[X]];I--){
        if(Block[I]==Block[I+Jump[I]]){
            Step[I]=Step[I+Jump[I]]+1,Get[I]=Get[I+Jump[I]];
        } else {
            Step[I]=1,Get[I]=I+Jump[I];
        }
    }
}
LL Calc(LL X){
    LL Ans=0;
    while(true){
        Ans+=Step[X];
        X=Get[X];
        if(X==0){
            return Ans;
        }
    }
}
int main(){
    LL I,J,K;
    N=Read();S=sqrt(N);
    SNum=N/S;
    if(N%S!=0){
        SNum++;
    }
    for(I=1;I<=SNum;I++){
        L[I]=(I-1)*S+1;
        R[I]=I*S;
    }R[SNum]=N;
    for(I=1;I<=N;I++){
        Jump[I]=Read(); 
        Block[I]=(I-1)/S+1;
    }
    for(I=N;I;I--){
        if(I+Jump[I]>N){
            Step[I]=1;
        } else if (Block[I]==Block[I+Jump[I]]) {
            Step[I]=Step[I+Jump[I]]+1;Get[I]=Get[I+Jump[I]];
        } else {
            Step[I]=1,Get[I]=I+Jump[I];
        }
    }
    M=Read();
    for(I=1;I<=M;I++){
        K=Read();
        if(K==1){
            LL X=Read()+1;
            Write(Calc(X)),putchar('\n');
        } else {
            LL X=Read()+1,Y=Read();
            Update(X,Y);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/81010023
今日推荐