离线 log 算法

文章介绍了CDQ分治作为一种优秀的离线算法,主要用于解决偏序问题,通过分治策略降低空间复杂度。同时提到了整体二分法,适用于多组询问且能通过二分答案值域解决的题目,以及线段树分治,适合处理具有时间段的修改操作和询问问题。这些算法在处理复杂问题时能有效优化时间和空间效率。
摘要由CSDN通过智能技术生成

CDQ分治

一种空间复杂度(和时间常数?)优秀的离线算法。

简介:对于偏序问题,将其中一维(记为 x x x)排序,考虑将当前区间 [ 1 , n ] [1, n] [1,n] 以中点 m i d mid mid 分开,形成子区间 [ 1 , m i d ] [1, mid] [1,mid] [ m i d + 1 , r ] [mid+1, r] [mid+1,r]。处理 [ 1 , n ] [1, n] [1,n] 时只考虑从两子区间出发, x x x 跨越 m i d mid mid 的贡献;然后递归到子区间 [ 1 , m i d ] [1, mid] [1,mid] [ m i d + 1 , r ] [mid+1, r] [mid+1,r] 中。显然一个点对仅有第一次跨越mid是被统计(即第一次跨越之前,两点在一边;第一次跨越之后,两点不会出现在同一区间中)。

一般顺序,可以用于偏序计数问题:

void cdq(int l, int r){
	if(l==r) return ;
	int mid=(l+r)/2;
	cdq(l, mid); cdq(mid+1, r);
	work...
}

例题:
P3810 【模板】三维偏序(陌上花开)
P4169 [Violet]天使玩偶/SJY摆棋子

对于偏序计数的常见trick,有加入时间维离线,可以解决较为简单的动态问题。
例题:
P3157 [CQOI2011]动态逆序对

在cdq辅助转移偏序dp时,顺序会变为

void cdq(int l, int r){
	if(l==r) return ;
	int mid=(l+r)/2;
	cdq(l, mid);
	work...
	cdq(mid+1, r);
}

考虑在dag模型类dp过程中,用来转移的状态应是转移完全完成的。这种转移可以保证用 [ 1 , m i d ] [1, mid] [1,mid] 中的值更新 [ m i d + 1 , r ] [mid+1, r] [mid+1,r] 时, [ 1 , m i d ] [1, mid] [1,mid] 的值更新完备。而上述的“一般转移”则不行,因为在其递归 [ m i d + 1 , r ] [mid+1, r] [mid+1,r] 时, [ 1 , m i d ] [1, mid] [1,mid] [ m i d + 1 , r ] [mid+1, r] [mid+1,r] 的转移尚未完成。当然,如果更新方向相反,cdq分治的顺序也要调整反过来。

例题:
P2487 [SDOI2011]拦截导弹
P4093 [HEOI2016/TJOI2016]序列

cdq同样可以用于带修问题中。具体的,将修改和询问都加入时间维后放在一个序列中,仿照上文的trick将时间维cdq掉。我们需要考虑的就是每一个 修改-询问 的点对中修改对询问的影响。这需要修改具有可叠加性,即前面的修改需要被后面的修改覆盖时易取消。

例题:
CF848C Goodbye Souvenir

总结:
正常处理k维偏序相关的题目时,对一维扫描,则余下k-1维必须使用数据结构动态维护。而cdq分治对于第一维采用分治处理,消去了第一维的影响,故可以扫描第二维,余下k-2维使用数据结构。

而cdq的好处是,在通常最高是三维的问题中,二维数据结构的空间复杂度普遍在 O ( n l o g n ) O(nlogn) O(nlogn),而cdq仅需一维数据结构支持,空间复杂度仅为 O ( n ) O(n) O(n)

整体二分

针对一类包含多组询问,单独的一个询问可以通过在答案值域上二分解决的题目的算法。通过遍历二分答案的过程中可能产生的值域(可以想象成答案值域形成的线段树上的全体区间),一次性确定所有询问的答案。可以发现其求得答案的顺序和询问顺序无关(事实上是按答案值域递增的顺序),故其为离线算法。

分析节省时间复杂度的原理。我们设答案值域大小为 N N N,询问组数为 M M M,在将值域上一个点计入二分统计中的复杂度为 O ( S ) O(S) O(S),二分中一次check的查询的复杂度为 O ( C ) O(C) O(C)。若单独做一组询问,复杂度为 O ( C l o g N + N S ) O(ClogN+NS) O(ClogN+NS)。顺序回答问题,总复杂度为 O ( M C l o g N + M N S ) O(MClogN+MNS) O(MClogN+MNS)。对于整体二分,每个值域上的点只会被插入 l o g N logN logN 次。总复杂度变为 O ( M C l o g N + N S l o g N ) O(MClogN+NSlogN) O(MClogN+NSlogN)。可以发现整体二分对于一个值域区间在计入一次后,对所有答案包含在此区间中的询问统一check,节省了原来的大量重复计入。

题目示例:
P3332 [ZJOI2013]K大数查询
P3834 【模板】可持久化线段树 2

线段树分治

一种解决一类特殊带修问题的算法。

一个问题需要使用线段树分治,一般有以下特点:
1.有多组修改,每个修改的影响持续一个时间段 [ l , r ] [l, r] [l,r],即在 [ l , r ] [l, r] [l,r] 时间段以内修改生效,此外的时候无效。亦可以表现为需要支持修改撤销。
2.修改操作的复合满足交换律(即与顺序无关)。
3.对于可行的维护方法,修改操作在与其他修改复合过后难以撤销。可以理解为只容易撤销末尾的操作(沿着操作栈撤销)。
4.多组询问,每次询问的时间不同。

我们考虑将时间轴建成线段树,每一个操作对应的时间段可以在对应 l o g log log 个区间。将每个操作拆分后丢到线段树上的对应区间中去,询问丢到对应叶子节点上,然后我们遍历线段树,并保证仅进行了从根到当前点的路径中包含的修改操作(即维护到根的操作链,在返回父亲时只需要撤回自己节点上的操作即可)。到叶子节点时回答询问。

题目示例:
P9168 [省选联考 2023] 人员调度

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值