分块算法&BZOJ2002

题目传送门

第一次接触分块......

分块查找是折半查找和顺序查找的一种改进方法,分块查找由于只要求索引表是有序的,对块内节点没有排序要求,因此特别适合于节点动态变化的情况。

分块修改理论复杂度为O(N/M),M为块的大小,有基本不等式得M=Sqrt(N)时较优。

分块将原数组分为M块,对M块的信息进行维护。

这道题每个点记录一个它跳到下一个不是同一块的点是哪个点及需要几步跳到那个点。

code:

/**************************************************************
    Problem: 2002
    User: yekehe
    Language: C++
    Result: Accepted
    Time:1648 ms
    Memory:3956 kb
****************************************************************/
 
#include <cstdio>
#include <cmath>
using namespace std;
 
int read()
{
    char c;while(c=getchar(),c<'0'||c>'9');
    int x=c-'0';while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';
    return x;
}
 
const int MAXN=200005;
int N,M,Q,a[MAXN];
int belong[MAXN],nxt[MAXN],J[MAXN];
 
int Query(int x)
{
    int tot=0;
        while(x<=N){
            tot+=J[x];
            x=nxt[x];
        }
    return tot;
}
 
void Change(int x,int y)
{
    int l=(belong[x]-1)*M+1,r=belong[x]*M;
    a[x]=y;
        for(int i=x;i>=l;i--){
            if(i+a[i]>r)nxt[i]=i+a[i],J[i]=1;
            else nxt[i]=nxt[i+a[i]],J[i]=J[i+a[i]]+1;
        }
    return ;
}
 
int main()
{
    N=read();M=sqrt(N);
    if(M*M<N)M++;
    register int i,j;
        for(i=1;i<=N;i++)a[i]=read();
    j=1;
        for(i=1;i<=M;i++)
            for(;j<=i*M&&j<=N;j++)
                belong[j]=i;
        for(i=1;i<=N;i++){
            int Ks=0;
                for(j=i;j<=N&&belong[j]==belong[i];j+=a[j])Ks++;
            nxt[i]=(j>N?N+1:j);
            J[i]=Ks;
        }
    Q=read();
        while(Q--){
            int o=read(),x=read();
            if(o==1)printf("%d\n",Query(x+1));
            else Change(x+1,read());
        }
}

 

posted @ 2018-03-16 12:00  Cptraser  阅读(132)  评论(0编辑  收藏