数据结构总结

来源:互联网 发布:淘宝服装卡片祝福语 编辑:程序博客网 时间:2024/06/08 20:08

分类

1:并查集

2:单调队列、单调栈

3:堆、优先队列

4:树状数组

5:线段树

6:树链剖分

7:主席树

8:平衡树

9:lct

10:树套树

11:分块、莫队

 

并查集

并查集主要的用途

1:维护并查集判断是否在一个集合。

2:快速找到下一个位置,poj1456——配合贪心。

 

所遇技巧

1:分点并差集,当中分点的意义就是,根据一个物的几种状态进行分点,根据给出的条件,在相关的不同点的不同或相同状态间连边。处于一个集合,就代表他们状态是相关联的,是可以互相推出的。

同时像这种可以关系推倒的,2sat也是很常见。

2:带权并查集,维护到根节点的距离。 ——HNOI2005  狡猾的商人:带权并查集维护到根的距离,以配合差分。

 

应用:克鲁斯卡尔,lca Tarjan

 //题量不够,不好总结题型

 

 单调队列,单调栈

1:滑动窗口类型的单调队列

2:单调队列优化dp

一、一般的单调队列优化

二、斜率优化等配合凸包斜率的优化

 

堆,优先队列

只要是要求最值的,且只包含插入和询问的这种,就可以通过堆来优化到log(n)

 1:优化dp

 2:贪心:bzoj2802

//题量不够,不好总结

 

树状数组

1:二维树状数组,可以尝试推出式子,对于不同的次项,分别维护树状数组。

2:求逆序对,包括动态逆序对

3:权值树状数组——询问比一个数小的个数

4:有一些需要功能比较少的维护数据,就可以用树状数组代替线段树,像相乘、相加、取异或等连着带修改,都可以用这个来解决

本质就是优化了前缀和。

 

注意一般的树状数组要满足区间减法,可以化作两个前缀答案相减的问题才可以用。

它最基础的内容:

1:区间加---单点查询

2:单点加----区间查询

在这些情况下优先考虑树状数组,如果可以就尽量避免线段树。


 

线段树

1:纯粹数据结构题,练代码能力的

2:线段树优化dp,其实就是分析题目发现:需要区间更新单点更新,单点取值的问题就完全可以用线段树来优化。

3:线段树作为题目基本解法的辅助工具

 

超哥线段树,维护直线,实际上是运用了标记永久化思想。标记永久化许多时候可以精简代码。

 

动态开点线段树,题目可以考虑对每一种权值或颜色等,建线段树,一般来说会mle,但是当我们用动态开点线段树,均摊复杂度分析会没有问题。

同时配合线段树合并,这个线段树合并可以是权值线段树,我们知道n个单权值的线段树合起来n log n的时间,有的时候就可以代替平衡树启发式合并。

merge操作。

由此我们可以对于每一个建立动开权值线段树,支持维护多个集合,求集合第k大,求集合小于一个数的个数,插入,以及合并。

 

up的时候注意边界就好。


树链剖分

1:只做过裸题。

2:还有就是根据最多log(n)个重边的性质,进行处理(hdu4897难)

树链剖分求lca常数小。

还有长链剖分,优化dp。

主席树

1:实质就是多个线段树套在一起,这里是权值线段树

解决的问题:查询区间内一个权值在[L,R]之间的数的个数(或者其它,第k大)

要满足区间减法才可以——就是l~r的答案可以从1~r的答案减去1~l-1得出来。

关键是查询区间在某个值之下的个数


 

平衡树,set

splay:维护序列问题比较经典,基本的平衡树操作则常数会大一些。

有一些题目,暴力算法需要合并,我们也可以考虑splay启发式合并。

 

set,当只需要插入、删除、求前驱后继等,就可以直接用set。需要size域的时候就不行了


lct

只会模板:判断一个两点是否在一颗树,换根,断开一条边,连接一条边,维护路径的数据(路径更新,询问等等)。

lct实际上维护连通性,当然我们可以分析题目的性质,如果题目的数学模型,断边、连边,等等,可以考虑他们与lct操作的对应关系。

 

lct维护最大最小生成树也是很常用的,边作点来存在lct上。

 

注意,还有维护用lct维护直径这一类,经典应用。

树套树

线段树套平衡树:做过裸题。

线段树套线段树:不会、

实际上不是什么神奇的东西,还是很暴力的。

 

kd-tree

kd-tree方便处理多维偏序的问题,以及经典的最近最远点对,也可以处理矩形权值和的问题,这些查询都是依赖于估价函数搜索。

kdtree带修改很暴力的一种方法是,根n重构法。

还有一些数学问题通过建模转化为求一个半平面的值,也是可以kdtree的。

 

脑补了一个:

考虑动态开点kdtree,建立严格的平衡结构。

对于一个n*n的棋盘,我们将(n/2,n/2)这个点作为根,我每次插入一个点时,

把沿途所有点都加上,不断缩小区域,知道到那个点所处的位置,一共会新建log n个节点,复杂度科学。


 

分块,莫队

莫队:其实就是优化了顺序,把n^2的暴力优化到了n^1/2了,要能够支持快速加入一个边界的值。

优化:排序时,奇数块r递增,偶数块r递减,可以使常数减小一倍。

带修改莫队:O(n^3/5) ,就是将时间也作为关键字排序。

 

分块:其实是可以很暴力的,各种重构的情况都有可能会有,毕竟是一个暴力偏分算法。——本质还是没有学透,距离“万物皆可分块”的水平还有一段距离。

 

序列分块:就是分整块和零散的部分处理。

 

经典的预处理思路有:

 

技巧:

1:f【i】【j】是从第i块到第j块的答案

2:f【i】【j】是从第i块到第j个位置的答案

例如区间众数,和 求区间出现偶数次的数的个数 ,可以用以上方法。

同时维护一些其他信息

——g【i】【j】,表示到第i块,j元素出现的次数,以此配合思路一,也正好保证了空间复杂度,n sqrt  n;

零碎的部分就靠维护的信息来统计的。

 

技巧:

在一些分块题目中我们需要动态维护一个前缀和,是有修改的,可以树状数组处理,复杂度 n sqrt n  log n

我们可以同时将,前缀和数组分块,这样更新O(sqrt n),查询 O(1),这就把log去掉了

 

技巧:

给出长度为n的序列,m个区间,每次询问,第l个到第r个区间答案的和。需要在线修改。

很经典的,我们可以考虑对m个区间分块,每一块f【i】【j】表示第i块有多少个区间包含j位置,以此我们就可以修改统计了。

可见分块的预处理非常关键,需要开发创造性思维。

 

可持久化分块:主题思路就是每次更新,新建一块,其他的不变。

块状链表:和普通分块不同的是,这个可以支持插入,一般来说当一块过大后就将它分成两块。

 

分块技巧:有的分块需要你处理,区间内复杂情况产生贡献(bzoj3669和区间众数和作诗),但是这样我们不好处理,同时有个特点是我们通过维护

别的数据结构,可以方便的处理一个元素在区间对应产生的贡献是多少,那么我们就可以进行分块,预处理某段到某段的答案,小部分数据结构维护来搞。
 

离线数据结构问题的常用技巧

1:正序转倒序,删除转插入等等。

 

2:分治

整体二分,和cdq分治:

cdq分治主要考虑前面对于后面的贡献,对于带删除的问题可能不好处理,很经典的是k大数查询,可以使用线段树分治(下面);

而整体二分则是把询问答案在mid之前的放在左边,mid之后的放在右边,以此处理。

甚至在某些dp题中 ,也会用分治来做,其实cdq是考虑前面对后面的贡献和影响,而dp也正是由之前的状态转移而来的,正是满足无后效性,例如货币兑换。

 

3:线段树分治

1:插入  。。。。 2:删除。。。3:询问。。。

 

这样的题目我们可以考虑,对询问建线段树,对于每一个元素,记录他所能影响到的询问区间,然后再线段树对应的区间标记。

处理i答案时,

1:可以由i到根的路径上存的所有询问来统计,要保证元素在被分组的情况下可以支持贡献的快速合并,例如去最大值取和等等。

2:如果可以支持操作的执行和撤销(可能需要数据结构),我们可以考虑对整个线段树进行遍历,在回溯时撤销就好。

 

 

4:对于排列问题或者中位数问题,可以考虑,二分然后将序列转化成只有(0,1)(1,-1)等特殊序列便于处理。

 

5:对于区间不重复问题

1:建立pre,记录前驱,转化为求有多少位置pre小于左区间端点

2:有一些题目可以在从左到右扫的过程中,只用数据结构记录最后一个位置。

 

6:向量问题

以向量问题引出凸包,就是和向量点积最大的一定在凸包上。这当然可以套上上面的那些方法

 

7:对于一些二维问题,且每一个位置和周围都有关系,那么我们就可以考虑,枚举一维,同时用数据结构维护一维。

技巧,对于数据结构问题可以试着把问题所求,转化成sigema公式,尝试转化。例如把一些项提出来,提出来的可以尝试用数据结构维护。

 

8:很多时候我们需要维护无向图的联通性,类似这样会多个约束的问题,我们可以对于右端点排序,然后所有的那些等价的约束操作,我们只记录最后一个。

 

9:要充分利用,主席树求区间小于一个数的个数这个基本用途。

 

10:对于一些区间开根,区间除的神题,可以考虑转化为部分暴力+分析区间减法。 

 

 11:区间的gcd问题可以转化为,差分序列的gcd问题,这样也就方便支持了区间修改。

 

12:对于多维偏序的问题,我们可以考虑kdtree,或者排序一维,cdq分治一维,数据结构一维,来处理这样的三位偏序问题。

 

 13:有些题目需要不断的把信息合并,或是建立在树上,同样需要自下而上合并信息,这时候需要维护有序表,我们可以考虑平衡树启发式合并,

如果键值较小,线段树合并可以去一个log,复杂度更优。

 

0 0
原创粉丝点击