分块

分块

分块是将线段树的懒标记方法一般化,可证明通常情况下以 n \sqrt n n 分块是最优解。

分块思想核心: 整块打包维护 碎块逐个枚举

extern int a[MAX];//a[0]不用
extern int len,num;//len:每块长度,num:分块数量
vector<int>beg,ed,pos,sum,add;
//beg,ed:每块的始末下标 pos:每个下标所属的块 sum:每块区间和 add:整块增量标记
void init(){
    len=sqrt(n);
    num=n/len;
    if(n%len) num++;//处理尾部有碎块情形
    beg.resize(num),ed.resize(num),pos.resize(MAX),sum.resize(num),add.resize(num);
    for(int i=1;i<=num;i++){//获取第i块的首尾下标
        beg[i]=(i-1)*len+1;//上一块尾的下一个位置
        ed[i]=i*len;
    }
    ed[num]=n;//更新最后一碎块尾下标
    for(int i=1;i<=MAX;i++) pos[i]=(i-1)/len+1;//获取第i个下标所属的块
    for(int i=1;i<=num;i++)
        for(int j=beg[i];j<=ed[i];j++)
            sum[i]+=a[j];//获取每块区间和
}

区间修改

以在 [ l , r ] [l,r] [l,r]元素加d为例

extern int l,r,d;
void update(){
    int pl=pos[l],pr=pos[r];//获取l和r所属的块
    if(pl==pr){//l,r在相同块中
        for(int i=l;i<=r;i++) a[i]+=d;//在原数组上进行修改是为了能够进行区间查询
        sum[p]+=(r-l+1)*d;//更新该块区间之和
    }else{//l,r中间跨越了整块
        for(int i=l;i<=ed[pl];i++) a[i]+=d;//将l所属的块处理完
        sum[pl]+=(ed[pl]-l+1)*d;
        for(int i=pl+1;i<pr;i++) add[i]+=d;//处理中间的整块
        for(int i=beg[pr];i<=r;i++) a[i]+=d;
        sum[pr]+=(r-beg[pr]+1)*d;
    }
}

总结:涉及到更新碎片,只在原数组a和块区间和数组sum上更新,不更新add整块增量标记

区间查询

以查询 [ l , r ] [l,r] [l,r]之和为例

extern int l,r;
int query(){
    int pl=pos[l],pr=pos[r],ans=0;
    if(pl==pr){//l,r在相同块中
        for(int i=l;i<=r;i++) ans+=a[i];
        ans+=add[p]*(r-l+1);//此块可能被整体修改过
    }else{//l,r不在相同块中
     	for(int i=l;i<=en[l];i++) ans+=a[i];
        ans+=add[pl]*(en[l]-l+1);
        for(int i=pl+1;i<pr;i++) ans+=sum[i]+add[i]*(en[i]-beg[i]+1);//不能写成add[i]*len,因为无法确定r是否在最后一个碎块上
        for(int i=beg[pr];i<=r;i++) ans+=a[i];
        ans+=add[pr]*(r-beg[pr]+1);
    }
    return ans;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值