您的位置:首页 > 其它

分块算法简单介绍

2018-04-04 19:59 225 查看
分块算法,一开始看到时总感觉它很高级,学过之后才知道它比线段树还好理解.
分块算法其实就是一个稍微优美一点的暴力算法.
分块算法的思想就是把一个数列分成很多块来处理,每当区间操作完整包括整块时直接在块的标记上处理,否则暴力处理.
就像一个数列[1..1000000],分块算法的思想就是把这个数列拆成[1..1000],[1001..2000],[2001..3000],...,[1000*n+1..1000*(n+1)],...,[999001..1000000]这些块,然后维护每一个块的标记.
一般来说假设一个数列有n个元素的话,就拆成sqrt(n)块来处理,这样份快递效率最坏情况下大概是O(3*sqrt(n)),省略常数后就是O(sqrt(n)),最稳定.
至于怎么维护标记,就如线段树.
其实我们可以把线段树看成把一个序列分成两块,然后再把他的子块分别分成两块,然后再分...
我们就来说说怎么用分块来维护区间加,单点查询.
首先分块,每块的长度我用了200.
每块维护一个标记bl[i],表示第i个块每个数都加有的数是多少.
然后我们考虑如何区间加.
区间[L..R]有两种情况:1.包含完整的块;2.不包含完整的块.
怎么判断呢?直接把指针L往R移,不停的L++,直到L是一个块的左边界或触碰到了R.
前者的条件是L mod bls=1(一下用bls代表每个块的长度),后者的条件是L>R.
之后用R往L移,直到R是一个块的右边界或触碰到了L.
前者的条件是R mod bls=0,后者的条件是L<R.
若这是L>R,就可以return了.
不然你就修改块了.
代码如下:inline void add(int L,int R,int num){
for (;L%200!=1&&L<=R;L++)
p[L]+=num;
for (;R%200!=0&&R>=L;R--)
p[R]+=num;
if (R<L) return;
for (int i=L/200+1;i<=R/200;i++)
bl[i]+=num;
}不用L执行完判断一次,R执行完判断一次,因为假如L执行完R<L了,那么R就不会执行了.
然后就是查询了.
查询的话直接把它的值与他所处块的标记相加就行了.
代码如下:inline int query(int X){
return p[X]+bl[(X-1)/200+1];
}这就是分块的简单讨论了.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: