萌新瞎讲【分块】

参考自:黄学长的分块入门 推荐!
信息学中的分块思想.pdf(百度就能百度到文件)这个有些错误…

分块的思想

简述

将规模为n的问题,分成 n 块,每块规模也是 n ,那么对块内的操作和整个范围的操作的复杂度平均,可以在较优的空间复杂度下,将每次操作的复杂度降低到\sqrt{n} ,以较低的编码 复杂度解决问题。

入门1

我们先来思考:原序列元素<—>所在块的对应关系

initially, 我们分好了块。
对于原序列元素a[ pos ],在哪个块: pos1n+1 ;
so,我们可以维护哪些信息?
原序列的每个元素 and 块 and …

题目:给出一个长为n的数列,以及n个操作,操作涉及区间法,单点查值。

分块思想:

先把每个元素分块包装,就是分块(堆),拿一个属性,去代表一段区间的属性。
这里有两个“加法”标记:块的/单个元素;
当 “区间[Left, Right]加 + val” 的时候,
1. 如果Left, Right 在同一个块,直接暴力维护单点标记,复杂度O( n );
2. 不在同一个块,
对于区间[Left,Left所在块的右端点]&&[Right所在块的左端点]暴力维护单点标记,复杂度O( n );
对于区间[Left所在块+1,Right所在块-1]这些块,进行维护块的加法标记,复杂度O( n );
对于 m 次询问,总的复杂度:m n .

代码注意:

块区间大小:s = n ;
原序列元素a[ pos ]的块位置:belong[ pos ] = pos1s+1 ;
原序列元素a[ pos ]的块的左端点:(belong[ pos ] - 1) * s + 1;
原序列元素a[ pos ]的块的右端点:belong[ pos ] * s;

代码具体实现:

PS: 这里单个元素维护数组直取代了原序元素数组;

while(m--) //操作数
{
    scanf("%d",&op);
    if(op)  //区间加
    {
        scanf("%d%d%d",&Left,&Right,&val);
        //维护Left所在块
        for(int i=Left; i<=min(bel[Left]*s,Right); i++) v[i]+=val;
        //维护Right所在块
        if(bel[Left] != bel[Right])
        {
            for(int i=(bel[Right]-1)*s+1; i<=Right; i++) v[i]+=val;
        }
        //维护块
        for(int i=bel[Left]+1; i<=bel[Right]-1; i++) vtag[i]+=val;
    }
    else    //查询
    {
        scanf("%d",&pos);
       printf("%d\n",v[pos]+vtag[bel[pos]]);
    }
}
基础练习1、

HDU1754
单点更新,区间求最值。
POJ3468
区间加,询问区间和。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值