基本原理:通过将区间分成两个区间,来将问题分成两个子问题。
一些基本问题
一.求所有区间的最大值之和
- 对于一段区间[l,r][l,r][l,r],我们找出他们的最大值的位置x,这个位置的贡献即为在[l,r][l,r][l,r]范围内通过x的一些区间。
- 这些区间的总个数即为(x−l+1)∗(r−x+1)(x-l+1)*(r-x+1)(x−l+1)∗(r−x+1)
- 通过乘法原理很容易得到
- 总的方案即为a[x]∗(x−l+1)∗(r−l+1)a[x]*(x-l+1)*(r-l+1)a[x]∗(x−l+1)∗(r−l+1)
- 区间可通过分治枚举得到
- 维护最大值用数据结构即可
二、区间统计:给定 a[1…n],求有几个区间 [L,R] 满足 a[L] or a[L+1]…or a[R]>max(a[L…R])
- 这道题我们需要考虑ororor的性质
- 对于一个数x,x ororor 一串数,它的数值肯定只增不减
- 我们考虑何时会增加
- 对于x or yx\ or\ yx or y,将x和y二进制拆分,如果x的第i位与y的第i位不相等,那么很显然x的数值会增加
- 根据这个性质我们可以用一个数组P[i]表示二进制拆分后第i位是一的左边的数的下标的最大值,右边也是同样
- 每次找到一个最大值x,枚举x的二进制位数,当x的第i位是0时,就可以用数组来知道不与当前数为同一个子集的数的位置,统计方法仍然跟一类似
三、旅行者:给定一张 n*m 的带正权两格图,有 Q 组询问,每次询问两对点之间的最短路
- 这题似乎比较难,这里只能说一下大概的思路
- 对于每个网格矩阵,分治出较长边的中点,对于两边的点,距离可分为左边的点到mid的距离与mid的距离到右边的点的距离
- 基于这种操作,不断的进行分治就可以
- //具体细节我并没有实现。。这里只是一个上课的印象,大体的思路
二分:二分其实是对答案分治
CDQ分治:把 [L,R] 分成 [L,mid] 和 [mid+1,R],考虑左边对右边的贡献。
.
例题:
缺一背包问题:给定 n 个物品的重量 W[i] 和价值 V[i],Q次询问,每次询问对除了第 i 个物品以外的物品 01 背包后重量不超过 S 的最大价值
- 考虑cdq分治,不断递归分治,先将左区间([1..L−1][1..L-1][1..L−1])的数组传到右边区间([R+1...n][R+1...n][R+1...n]),用左边数组的值做右边的值,这时不做中间递归到的区间,就相当于忽略了中间的数
- 不断递归,当递归到(l==r)(l==r)(l==r)时,就相当于时忽略了这么一个数,就可以预处理出解决了答案
- 也许吧,我也不怎么确定。。
点分治:区间分治的复杂度保证是由于每次分成<=n/2的区间,树每次分成<=n/2的子树
点分治基本实现:一般解决树上的路径问题。为了实现稳定,每次找树的重心进行分治,将路径和分成经过根与不经过根的两条,如果不经过根,则可以继续递归变成经过跟的问题。具体问题具体实现