![](https://img-blog.csdnimg.cn/20201014180756738.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
数据结构
数据结构算法记录
run around
这个作者很懒,什么都没留下…
展开
-
红黑树原理与代码
红黑树笔记原创 2023-02-06 14:29:43 · 314 阅读 · 0 评论 -
左式堆代码
struct node{ int val; int len; // 最短路径长度 node *lc,*rc; node(int a,int b,int c) { val = a; siz = b; len = c; lc = NULL; rc = NULL; }};void update(node *a) { // 更新当前节点信息 node *l = a->lc; node *r = a->rc; int len1 = 0; int len2原创 2022-05-26 10:36:49 · 139 阅读 · 0 评论 -
线段树分裂与合并
对于动态开点的线段树来说,当有很多棵线段树时,我们可以进行线段树合并,合并两棵线段树的复杂度为两棵线段树相同节点的数m*logm。将y这棵线段树合并到x这棵线段树,对于x没有y有的节点,直接复制y的就行,x有y没有的不用管,都有的加起来即可。void insert(int &now,int l,int r,int p,int v) //动态开点,将p位置的值加v{ if( now == 0 ) now = ++cnt; if( l == r ) { a[now].maxt +=原创 2021-03-28 22:18:49 · 468 阅读 · 0 评论 -
笛卡尔树
笛卡尔树上的每个点都是一个二元对(x,y),树对于x来说是一棵二叉搜索树,对于y来说是一个堆。对于x序已经单调的一个序列,可以O(n)建出笛卡尔树。顺序遍历对于新加进来的点i,找到第一个y小于等于它的点v(这里是小根堆),那么v的右子树就是i了,如果v有右子树,那么这个右子树作为i的左子树。如果没有这个点,那么i就是根了。int a[maxn],sta[maxn],l[maxn],r[maxn];int top = 0;int build(int n) //返回笛卡尔树的根{ int原创 2021-03-04 12:38:52 · 296 阅读 · 1 评论 -
无旋treap(fhq treap)
普通平衡树/*无旋treap(fhq treap)treap是二叉搜索树结合二叉堆来的,它保证树上任意节点,右节点值一定大于当前节点,儿子节点的索引一定小于父亲节点 对于任意一个点随机赋索引,这样的树就保证了随机,从而不会被卡链无旋treap主要引入了分裂和合并两个操作,从而可用来处理很多问题 */#include <iostream>#include <cstdlib>#include <ctime>using namespace std;c原创 2021-02-26 21:52:22 · 336 阅读 · 0 评论 -
线段树分治
线段树分治是一种离线做法,处理的是某种修改对询问的影响,这种影响可以独立也可以不独立。关键是把一个修改看成一个区间,每个询问是一个叶子。修改是在线段树上打标记。这里把询问看做一个时间点,而修改对应一个时间区间的修改。做法:在线段树上记录要操作的时间区间,dfs依次执行这一操作,一直到根节点来回答询问,离开时将其撤销。题目: 有两种操作,一种是将两个点连一条边,另一种就是询问这个点所在的连通块的点数,但是这个边的有效时间只有k天。每次操作过一天。分析: 如果没有有效时间的话,就是并查集的裸题。那么一次原创 2021-01-20 22:51:23 · 1072 阅读 · 0 评论 -
虚树
/*虚树,是对于一棵给定的树,构造一棵新的树使得总结点数最小且包含指定的某几个节点和他们的LCA。虚树常常用于处理树上的给定点的问题,常常多组访问,总访问点数在1e5内 先预处理整棵树lca和dfs序,接下来是对于每组询问的构造。虚树的构建是一个增量算法,要首先将指定的这k个点按照dfs序排序,然后按照顺序一一加入,强行先加入根节点以方便后面的处理。后面流程看代码 */ #include <iostream>#include <vector>#include原创 2020-10-10 17:25:55 · 206 阅读 · 1 评论 -
dsu on tree(树上启发式合并)
/*树上启发式合并用于处理离线查询的子树问题第一次先求出重儿子第二次dfs的过程中,先计算轻儿子,贡献不保留,再计算重儿子,贡献保留最后再加上轻儿子的贡献,计算出当前节点的值 复杂度为O(nlogn) */ /*每个节点都有一个颜色编号 计算一棵以1为根的树的以每个节点为根的子树中颜色最多的颜色编号和这题中子树的贡献就在于cnt数组,用来计数颜色出现了多少次 */ #include <iostream>#include <vector>using n原创 2020-09-01 10:40:36 · 163 阅读 · 0 评论 -
树链剖分
树链剖分之重链剖分重儿子:一个节点的所有儿子中,大小最大的那个轻儿子:一个节点除了重儿子以外的所有的儿子重链:从一个轻儿子开始(包括根),一路往重儿子走,连出的链叫重链需要两次dfs第一次求重儿子等一系列的信息(结点的父亲,结点的重儿子,结点的深度,结点的大小)第二次dfs标记时间戳形成dfs序,第二次dfs优先往重儿子走,这样所有的重链的dfs序都是连续的(结点权值的dfs序,当前dfs序对应的权值,当前结点所在重链的头是谁,头的头是自己)复杂度:O(m*(logn)^2)/*利用df原创 2020-08-31 15:51:18 · 81 阅读 · 0 评论 -
可持久化并查集
/*可持久化并查集并查集的本质就是数组,所以可持久化并查集就是可持久化数组但是并查集的路径压缩不能用了,因为路径压缩会改变fa数组,在可持久化里,改变就意味着log的空间复杂度,所以不用路径压缩,改为秩优化,即将深度小的并到深度大的所以需要维护两个可持久化数组,开两倍空间 */ #include <iostream>using namespace std;const int maxn = 2e5 + 5;int rootfa[maxn],rootdep[maxn],cn原创 2020-08-29 10:04:00 · 1050 阅读 · 0 评论 -
可持久化数组
/*可持久化数组操作1:修改某历史版本的某一位置的元素操作2:查询某历史版本的某一位置的元素每次操作后都会有新的版本实现上还是采用主席树用线段树维护一个数组 主席树则维护了每个版本的线段树 动态开点,每个版本复制修改前的版本,只修改要修改的部分,空间为log */ #include <iostream>using namespace std;const int maxn = 1e6 + 5;int a[maxn],root[maxn],cnt;struct n原创 2020-08-27 21:50:39 · 205 阅读 · 0 评论 -
主席树总结
/*主席树的本质就是前缀的权值线段树维护n个权值线段树,第i个权值线段树表示[1...i]这些数构成的权值线段树对于第i个权值线段树,只需要用第i-1的根,再维护那个改变的值,所用的空间为log 查询区间第k小时用R的权值线段树减去L-1的权值线段树即可 */ //静态区间第k大 #include <iostream>#include <vector>#include <algorithm>using namespace std;const in原创 2020-08-27 11:36:10 · 121 阅读 · 0 评论 -
扫描线
/*扫描线算法:计算n个矩形的并维护一条与y轴平行的线,顺序扫描,用线段树维护对应y轴的长度,相乘即可*/#include #include using namespace std;const int maxn = 2e5 + 5;typedef long long ll;struct line{ //line用来记录矩阵的竖线,x坐标,y1,y2和是否是左边还是右边int x,y1,y2,state;bool operator<(const line&n)const原创 2020-07-10 15:55:05 · 229 阅读 · 1 评论 -
dfs序及其应用
dfs序是用来处理子树一类问题的,可以把子树问题转化为区间问题,以便借助线段树或树状数组处理。根据dfs的顺序来给节点编号,在进入这个节点时更新in数组,出去的时候更新out数组,这样以i为根的子树的操作就可以变成区间[in[i]…out[i]]的操作了。int in[100005],out[100005];int tot = 1;void dfs(int x,int fa){ in[...原创 2020-03-23 00:01:27 · 297 阅读 · 0 评论 -
字典树
#include <iostream>using namespace std;const int maxn = 1e6;int trie[maxn*32][26]; //trie[a][b]=c表示节点a的第b个儿子为c//用边来存放字符信息,比如第一个儿子的边为a,第二个为b//点的总数可能很多,要认真分析出最大值,儿子数取决于每个位的取值范围 int tot =...原创 2020-03-06 11:51:49 · 64 阅读 · 0 评论 -
单调栈
单调栈主要用来找一个元素左边第一个比它小(大)的元素例如我们需要查找每一个元素向左第一个比它小的元素,我们只要维护一个单调增的序列(从栈底到栈顶,下标依次增大,值也依次增大)。因为对于任意的i,j,若i>j且a[i]<a[j],那么找第一个小于a[k]的答案时,必然不会选到a[j]。我们淘汰掉当前栈中大于等于即将入栈的元素,这样当前的栈顶就是我们需要的答案,最后再把当前元素入栈。...原创 2020-02-26 20:24:57 · 121 阅读 · 0 评论 -
权值线段树(序列第k大)
权值线段树就是在线段树的基础上,将每一个点作为一个桶。区间l到r表示从[l…r]这个数值之间的信息。每个节点维护一个数值的数量,表示[l…r]这个区间有多少个数。支持的操作:添加一个元素查找一个元素出现的次数查找区间的元素个数查询所有元素的第k大(小)元素/*权值线段树在线段树的基础上,将每一个点作为一个桶。区间l到r表示从[l...r]这个数值之间的信息。每个节点维护一个数值...原创 2020-02-03 13:59:07 · 932 阅读 · 0 评论 -
ST表
/*ST表:给定一段区间,求这段区间的最大/最小值 f[i][j]:记录[i~i+2^j-1]区间的最大值状态转移:将[i,j]平均分成两段f(i,j)的最大值即这两段的最大值中的最大值。f[i][j]=max(f[i][j-1],f[i+2^j-1][j-1])查询时给定l,r取k=log2(r-l+1)ans=max(f[l][k],f[r-2^k+1][k]) */ ...原创 2019-07-23 09:47:48 · 81 阅读 · 0 评论 -
树状数组
树状数组是与线段树实现的功能类似的数据结构,也是可以在log(n)的复杂度实现区间修改和区间查询。以简洁的代码和思路占优,十分容易实现前缀和。单点变化,区间查询#include <cstdio>using namespace std;typedef long long ll;ll c[500005]; //表示区间[i-lowbit(i)+1,i]的区间元素和 in...原创 2019-07-26 21:12:54 · 78 阅读 · 0 评论 -
线段树
#include <iostream>using namespace std;typedef long long ll;struct node{ //线段树节点,左右区间,区间和,lazy标记 ll l,r,sum,lazy; node() { l = r = sum = lazy = 0; } }a[400010];...原创 2019-07-19 18:56:42 · 94 阅读 · 0 评论 -
单调队列
单调队列有单调递增和单调递减两种,一般来讲,队列的队首是整个队列的最大值或最小值。一般我们用双端队列实现操作步骤若队列为空,将A[i]从队尾入队若队列不为空,将比A[i]大的元素都从队尾弹出,然后把A[i]入队若队列不为空且A[i]大于队尾,则直接从队尾把A[i]入队洛谷1440一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值。若前面的数不足...原创 2019-07-25 09:28:42 · 83 阅读 · 0 评论