浅谈离线分治算法

很多人似乎搞不清楚\(CDQ\)分治和整体二分有什么区别,但其实这两者区别极其之大,除了都是离线分治算法以外,可以说没有任何共同点。所以我特地在此把两者放在一起讲讲,搞清楚这两者之间不同之处与作用。

在接触离线分治算法之前,我们先来认识认识离线分治算法能解决的问题。

离线分治算法能解决的问题

离线分治算法能解决的问题一般都是对于给定数据支持修改与询问的问题。根据是否强制在线,可以将问题划分为在线/离线问题。根据是否带修改,可以将问题划分为动态/静态问题。

我们给修改和询问定义一个时间轴,按照一次读进来的顺序从小到大。在线问题则是需要对于每一次询问马上回答出它的答案,离线问题是我可以知道所有的操作之后,安排合理的顺序去统计答案,再一个个按时间轴上的位置输出。

不带修改或者所有修改都在询问之前的问题就叫做静态问题,否则就叫动态问题。有一件显而易见的事情,那就是静态问题比动态问题简单的多。

\(CDQ\)分治

\(CDQ\)分治是基于时间轴的分治算法。每一个询问的答案,受到初始数据与在时间轴上在它之前的修改的影响。那么我们就按时间分治,进行如下操作,假设\(solve(l,r)\)表示进行时间轴上区间\([l,r]\)的操作:

\(1\)\(solve(l,mid),solve(mid+1,r)\)\(2\)、计算\([l,mid]\)中的修改对\([mid+1,r]\)中询问的影响。

显然第\(2\)步是一个复杂度只和区间\([l,r]\)大小有关的静态问题,那么\(CDQ\)分治就成功的将一大个动态问题划分成了若干个静态问题。复杂度就是在\(O(nlogn)\)的基础上再乘上的每次操作在静态问题中的复杂度。

假设一个询问\(k\)属于区间\([mid+1,r]\),那么在\([mid+1,k]\)的修改会在\(solve(mid+1,r)\)这一步把贡献算到里面去,在第二步的时候\([l,mid]\)的修改对询问\(k\)的贡献也会被算进来。

这就是基于时间轴的分治算法。

模板题:https://www.cnblogs.com/AKMer/p/10416988.html

整体二分

整体二分是基于值域的分治算法。我们定义\(solve(l,r,S)\)\(S\)表示一个操作集合。这个函数表示处理答案在值域区间\([l,r]\)内的操作\(S\)

1、如果\(S\)为空集,那么直接退出。如果\(l==r\),那么就把\(S\)中的每个询问的答案都赋值为\(l\)。然后退出。

2、对于每个询问统计权值在值域区间\([l,mid]\)的数据会对它造成的贡献,如果贡献超过了需求,那么就说明这个询问的答案在\([l,mid]\),否则就在\([mid+1,r]\),并且子问题中需求要减去\([l,mid]\)对它的贡献。

3、递归处理子问题\(solve(l,mid,S'),solve(mid+1,r,S'')\)

这个复杂度也是\(O(nlogn)\)+静态问题复杂度的。因为把多个询问放在一起二分了,所以复杂度大大地降低了。

这就是基于值域的分治算法。

模板题:https://www.cnblogs.com/AKMer/p/10417032.html

posted @ 2019-02-21 21:48  AKMer  阅读(342)  评论(0编辑  收藏