前言
十几天前学了CDQ分治,总是忘记。今日恰巧有空,写博客加强记忆。
据说CDQ是发明这个算法的某位巨学。
优点
替代主席树等高级数据结构,降低常数,提高算法效率和稳定性,提高代码可靠性。
缺点
只能离线,碰到在线操作就不能使用。
基本思想
1.我们给定一系列问题,包括修改和查询某个数列。可以把这些问题排成序列,用区间
[
L
,
R
]
[L,R]
[L,R]表示。
2.分:递归处理子问题,分为左边区间
[
L
,
m
i
d
]
[L, mid]
[L,mid]和右边区间
[
m
i
d
+
1
,
R
]
[mid+1, R]
[mid+1,R]处理。
3.治:合并子问题,计算左边区间对右边区间的影响。
简单到炸是不是
基本应用
给定一个N个元素的序列a,初始值全部为0,对这个序列进行以下两种操作:
操作1:格式为1 x k,把位置x的元素加上k(位置从1标号到N)。
操作2:格式为2 x y,求出区间[x,y]内所有元素的和。
这是一个二维偏序问题,虽然可以用树状数组做。
每个操作用一个有序对(a,b)表示,其中a表示操作到来的时间,b表示操作的位置。
时间是默认有序的,所以我们在合并子问题的过程中,就按照b从小到大的顺序合并。
我们定义结构体Query包含3个元素:type,idx,val,其中idx表示操作的位置,type为1表示修改,val表示“加上的值”。
而对于查询,我们用前缀和的思想把他分解成两个操作:sum[1,y]-sum[1,x-1],
即分解成两次前缀和的查询。在合并的过程中,
type为2表示遇到了一个查询的左端点x-1,
需要把该查询的结果减去当前“加上的值的前缀和”,type为3表示遇到了一个查询的右端点y,
需要把查询的结果加上当前“加上的值的前缀和”,val表示“是第几个查询”。这样,我们就把每个操作转换成了带有附加信息的有序对(时间,位置),
然后对整个序列进行CDQ分治
——摘自这里