随笔分类 -  数据结构

摘要:假设我们需要一棵线段树,它要在可以维护普通线段树的操作的同时还可以查询历史版本。 最zz的做法当然是建出$m$棵线段树,时间和空间开销都是爆炸的,但是我们可以通过 每次尽可能使用原来的结点 来使复杂度降为$O(nlogn)$ 这样每次对于需要更改的结点,直接新建一个,而不是修改原来的结点,再储存一下 阅读全文
posted @ 2017-04-09 11:35 Krew 阅读(109) 评论(0) 推荐(0)
摘要:树链剖分就是把一个树分成了几条链。 轻重链剖分:对于一个结点,我们把它所有的儿子结点中子树结点数最大的那个成为重儿子,这样每个结点朝重儿子连边,称为重边,其他边称为轻边,最后重边就构成了若干链。 对于重链,我们用线段树维护信息,查询一条链把它从lca分为两条链,自底向上查询,轻边直接搞,重边在线段树 阅读全文
posted @ 2017-03-12 20:51 Krew 阅读(134) 评论(0) 推荐(0)
摘要:伸展树的作用和非旋转Treap类似,只不过它依然通过旋转来维持平衡,双旋的情况稍微复杂一点(单旋无法保证均摊$O(logn)$),主要有三种操作: splay(k):将第k大元素旋转至根节点 merge(x,y):合并两棵splay,返回新的根节点 split(x,k):将元素[1,k]和[k+1, 阅读全文
posted @ 2017-02-28 15:30 Krew 阅读(191) 评论(0) 推荐(0)
摘要:传统式的Treap通过旋转来保证查找效率,但这样有一个不好:旋转会破环树的形态,导致无法高效的在上面维护标记。而非旋转的Treap就没有这种问题,它通过分裂和合并操作来进行维护而不是旋转。 支持的操作: merge(x,y):将两棵根节点分别为x,y的树合并,返回新的树的根 split(x,k):将 阅读全文
posted @ 2017-02-27 19:09 Krew 阅读(219) 评论(0) 推荐(0)
摘要:用二叉堆实现优先队列是十分有效的,然而,有时候我们会遇到“合并两个堆”这样的问题,如果用二叉堆实现就只能启发式合并,复杂度为$O(nlogn)$,相反,用左偏树实现的优先队列就能很好的解决这类问题,复杂度也不错。 (这里没有讲解) 代码: 阅读全文
posted @ 2017-02-20 15:47 Krew 阅读(113) 评论(0) 推荐(0)
摘要:序列莫队: 有这样一类套路题:给出一个$[1,n]$的区间,每次询问区间$[l,r]$的某个值。 对于这类问题已有一个不错的“通解”:假设我们知道了区间$[l,r]$的答案,那么如果区间$[l 1,r]$,$[l+1,r]$,$[l,r 1]$,$[l,r+1]$的答案都能在$O(p)$的时间内计算 阅读全文
posted @ 2017-01-28 15:43 Krew 阅读(127) 评论(0) 推荐(0)
摘要:差分: 在我忘了哪年的NOIP题目——借教室中,由于一些选手的智(xia)慧(gao),出现了一种新的做法:前缀和差分。 举例来说,假设我们现在有一个长为$n$的数组,值初始为0,给出若干操作$[l,r]$,每次操作把区间$[l,r]$的所有数加1,在执行所有操作后查询一次各点的值。 我们暂且不管线 阅读全文
posted @ 2016-10-09 19:37 Krew 阅读(158) 评论(0) 推荐(0)
摘要:尺取法(Two Points)——两个log还是一个log? 很多二分答案的题目会要求每次查询数组中【瞎定义一个函数】小于给定常数的数目。 大多数时候我们都可以用固定左端点二分右端点的方式,单次复杂度为$O(nlogn)$,但是往往有更佳的方法——尺取法 以每次查询区间和小于给定常数的的区间个数为例 阅读全文
posted @ 2016-09-26 23:15 Krew 阅读(237) 评论(0) 推荐(0)
摘要:堆(heap) push:插入一个元素,O(logn) top:返回当前元素最小值,O(1) pop:将当前最小元素弹出队列,O(logn) 代码: include include include include define rep(i,x,y) for (int i=x;i=x;i ) usin 阅读全文
posted @ 2016-08-27 19:29 Krew 阅读(191) 评论(0) 推荐(0)
摘要:分块 瞎搞个玩意支持对一个数组区间求和,单点修改。 啊,已经有很多方法了? 朴素算法:O(1)修改,O(n)查询 前缀和:O(n)修改,O(1)查询 树状数组:O(logn)修改,O(logn)查询 看似好像齐全了……然而还是有个比朴素好的东西:分块 我们把整个数组分成sqrt(n)个部分,每个部分 阅读全文
posted @ 2016-06-18 21:57 Krew 阅读(163) 评论(0) 推荐(0)
摘要:正常的线段树 zkw线段树的区间修改实在是不明白…… 差分和前缀和的前缀和是什么gui…… 还是用正常的写了一发(数据大一定要用输入输出优化,大概能节省1/4的时间) 代码: include include include include define rep(i,x,y) for (int i=x 阅读全文
posted @ 2016-06-08 12:20 Krew 阅读(136) 评论(0) 推荐(0)
摘要:zkw线段树 传统线段树是基于递归的分治算法,常数太大,书写复杂度高。因此,清华大学的zkw提出了一种新的基于二进制运算的非递归线段树——zkw线段树。 操作: (1)区间查询: 我们让叶节点全部固定在最后一层,由于 查询是连续的 ,每一层至多访问两个节点,以最左边的节点为例,如果它是父亲的右儿子, 阅读全文
posted @ 2016-06-07 15:01 Krew 阅读(424) 评论(0) 推荐(0)
摘要:RMQ问题: 区间最小值问题(Range Mininum Query,RMQ)指的是这样一类问题:给出长度为n的序列,支持一个查询操作:Query(x,y),表示询问区间[x,y]的最小值。 暴力查询需要O(n)的时间,效率太低了,线段树也需要O(logn)的时间,Tarjan他老人家又出来了,提出 阅读全文
posted @ 2016-06-02 19:13 Krew 阅读(176) 评论(0) 推荐(0)
摘要:树状数组 树状数组(Binary Indexed Tree,BIT)是一种维护区间信息的数据结构。 对于长度为n的序列,维护n个子区间,在修改和查询时分为子区间维护。 原理蕴含在此图中: 每一个区间都可以分成若干个不相交子区间之和,其中x区间长度为lowbit(x)=x&( x) 操作: (1)ad 阅读全文
posted @ 2016-05-28 11:17 Krew 阅读(149) 评论(0) 推荐(0)
摘要:并查集: 并查集(union find set)是一种维护各个不相交集合之间的关系的数据 结构,可以用于维护图的连通分量或是变量之间的关系。 通常用森林表示法实现并查集,即为每个元素,维护一个F[i]表示它的父节点,初始时每个结点自成一棵树,每棵树中的元素表示当前集合中的元素。 操作: (1)uni 阅读全文
posted @ 2016-05-27 21:59 Krew 阅读(260) 评论(0) 推荐(0)
摘要:inorder_tree(k):打印树根为k的树的中序遍历 Search_tree(k):查找k节点是否存在 minum(k): 查找以k为根的子树最小值 maxnum(k):查找以k为根的子树最大值 post_node(k):查找结点k的后驱结点 pre_node(k):查找结点k的前趋结点 No 阅读全文
posted @ 2016-02-03 23:03 Krew 阅读(183) 评论(0) 推荐(0)