量产数据结构
概念:给一个序列,用树维护信息。
- 偏序类
- 树分治类
- 小Z的袜子类
一. 偏序类
1.偏序的概念
设 A 是一个非空集,P 是 A 上的一个关系,
若关系P是自反的、反对称的、和传递的,则称P是集合A上的偏序关系。
即P适合下列条件:
- (1)对任意的 a∈A , (a,a)∈P ;
- (2)若(a,b)∈P 且(b,a)∈P ,则 a=b ;
- (3)若(a,b)∈P , (b,c)∈P ,则(a,c)∈P ,
-
则称 P 是 A 上的一个偏序关系。
带偏序关系的 集合 A 称为 偏序集或半序集 。
若P是A上的一个偏序关系,我们用 a≤b 来表示(a,b)∈P。
举如下例子说明偏序关系:
1、实数集上的小于等于关系是一个偏序关系。
2、设 S 是集合,P(S)是 S 的所有子集构成的集合,
定义 P(S)中两个元素 A≤B 当且仅当 A 是 B 的子集,
即 A 包含于 B,则P(S)在这个关系下成为偏序集。
3、设 N 是正整数集,定义 m ≤ n 当且仅当m能整除n,不难验证这是一个偏序关系。
注意它不同于N上的自然序关系。 偏序是在集合 P 上的二元关系(≤),
它是自反的、反对称的、和传递的,就是说,对于所有 P 中的 a, b 和 c,有着:
a ≤ a (自反性); a ≤ b 且 b ≤ a 则 a = b (反对称性); a ≤ b 且 b ≤ c 则 a ≤ c (传递性)。
【定义简单化】
所谓偏序就是当你知道元素A,B,C时,元素A<B,且A<C,
但是B和C之间的关系却无法比较的现象。在ACM中,
此类的题目通常会告诉我们n个数组,每个元素的各属性对应于不同数组的同一位置的值 。
询问通常是回答比这元素小的有几个,或者是LIS这样的dp问题。
( LIS:最长上升(递增)子序列。)
通常有以下方法:排序,数据结构(树状数组,线段树,平衡树),cdq分治,分块。
2.偏序类---量产数据结构
即每次对满足多维(某维)的一个限制的所有数进行操作。
多维(某维)的限制:每个点 i 有 ai,bi,ci...不同的值。
操作具体:每次对每个值满足的某区间进行一次修改操作。
例如,对满足 l1<=ai<=r1 , l2<=bi<=r2 ...的 i 进行一次修改操作。
3.具体实现和维护
(1) Range Tree
范围树:狭义上的树套树.
- 能在O( logn^d )的复杂度内进行一次d维偏序的空间查询
- 能在O( logn^d )的复杂度内进行一次d维偏序的单点修改
- 空间为O( nlogn^(d-1) ),可以优化到O( n(logn/loglogn)^(d-1) )
如果要维护d维,出于方便,设每维的值大小是v的一个偏序。
*高维树状数组*
本质就是树状数组的嵌套。时间复杂度O( logv^d ),空间复杂度O( v^d )。
可以预先高维离散化来优化。时间复杂度O( logv^d ),空间复杂度O( nlogv^d )。
//普通树状数组写法
inline void add(int x,int y){ //元素修改(增加)
for(int i=x;i<=n;i+=lowbit(i))
t[i]+=y;
}
//二维树状数组+偏序写法
inline void add(int x,int y,int z){ //空间修改(增加)
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=n;j+=lowbit(j))
t[i][j]+=z;
}
其实高维树状数组一般只有二维。
二维树状数组