数据结构--分块

其实我认为分块并不完全算是一种数据结构,它应该是一种分段思想,但为了正式一点,还是写了这一篇文章。

首先放一道最基本的分块:

P3870 [TJOI2009] 开关 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

//code by SPzos
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#define ak return 0;
#define fo(i,j,k) for(register int i=j;i<=k;++i)
#define fd(i,j,k) for(register int i=j;i>=k;--i)
#define fh(i,x) for(register int i=head[x];i;i=e[i].nxt)
#define fv(i,x) for(register int i=0;i<v[x].size();++i)
using namespace std;
const int N=100010;
inline int read(){
    int ret=0,f=0;char ch=getchar(); 
    while(ch<'0' || ch>'9'){if(ch=='-') f=1;ch=getchar();}
    while(ch>='0' && ch<='9'){ret=(ret<<1)+(ret<<3)+ch-(1<<4)-(1<<5);ch=getchar();}
    return f?-ret:ret;
} 
int n,m,a[N],b[N],tag[N],ans[N],sq;
inline void change(int x,int y){
    fo(i,x,min(b[x]*sq,y)){
        ans[b[x]]-=(a[i]^tag[b[x]]);
        a[i]^=1;
        ans[b[x]]+=(a[i]^tag[b[x]]);
    }
    if(b[x]!=b[y])
    fo(i,(b[y]-1)*sq+1,y){
        ans[b[y]]-=(a[i]^tag[b[y]]);
        a[i]^=1;
        ans[b[y]]+=(a[i]^tag[b[y]]);
    }
    fo(i,b[x]+1,b[y]-1){
        tag[i]^=1;
        ans[i]=sq-ans[i];
    }
}
inline int query(int x,int y){
    int sum=0;
    fo(i,x,min(b[x]*sq,y)){
        sum+=(a[i]^tag[b[x]]);
    }
    fo(i,b[x]+1,b[y]-1) sum+=ans[i];
    if(b[x]!=b[y]) 
    fo(i,(b[y]-1)*sq+1,y){
        sum+=(a[i]^tag[b[y]]);
    }
    return sum;
}
int main(){
    n=read();m=read();
    sq=sqrt(n);
    fo(i,1,n) b[i]=(i-1)/sq+1;
    fo(i,1,m){
        int opt=read(),x=read(),y=read();
        if(opt) printf("%d\n",query(x,y));
        else change(x,y);
    }
    ak
} 

其实分块这个东西就是个优雅的暴力,把数列分成一块块的,如果能整体修改那就上懒标记,如果不能就直接暴力修改

这里提一个扩展,不算是分块,但是属于根号算法。

根号算法--不只是分块

P3396 哈希冲突 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

//code by SPzos
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#define fo(i,j,k) for(register int i=j;i<=k;++i)
#define fd(i,j,k) for(register int i=j;i>=k;--i)
#define fh(i,x) for(register int i=head[x];i;i=e[i].nxt)
#define fv(i,x) for(register int i=0;i<v[x].size();++i)
using namespace std;
const int N=150010;
inline int read(){
    int ret=0,f=0;char ch=getchar(); 
    while(ch<'0' || ch>'9'){if(ch=='-') f=1;ch=getchar();}
    while(ch>='0' && ch<='9'){ret=(ret<<1)+(ret<<3)+ch-(1<<4)-(1<<5);ch=getchar();}
    return f?-ret:ret;
} 
int n,m,val[N],ans[505][505];
int main(){
    n=read();m=read();
    int sq=sqrt(n);
    fo(i,1,n){
        val[i]=read();
        fo(j,1,sq){
        ans[j][i%j]+=val[i];
        }
    }
    while(m--){
        char ch[2];scanf("%s",ch);
        int x=read(),y=read();
        if(ch[0]=='A'){
            int as=0;
            if(x<=sq) as=ans[x][y];
            else{
                for(int i=y;i<=n;i+=x)
                    as+=val[i];
                }
                printf("%d\n",as);
        }
           else{
                fo(p,1,sq){
                    ans[p][x%p]-=val[x];
                    ans[p][x%p]+=y;
                }
                val[x]=y;
            }
        }
    return 0;
} 

预处理的复杂度为nlogn

问题询问为mlogn,因为模数比根号n更大,这就保证了数比根号N要小

总计(m+n)logn

这种算法确实是很妙,我目前也只是碰见了这一道。

上一篇:[考试总结]noip模拟55


下一篇:[考试总结]noip模拟50