7.9&7.11 DS
- 数据结构要形成自己的写法。
树状数组
一维树状数组
一些注意事项:
-
下标从 \(1\) 开始
-
\(\operatorname{lowbit}(x)=x\&-x\)
二维树状数组
- 区间修改 / 查询时对两维分别枚举 \(\operatorname{lowbit}\)
树状数组上二分
- 与线段树二分类似,判断当前状态对最终答案的贡献,根据大小进行二分。
线段树
线段树合并
- 把很多权值线段树合并起来
两种做法:
- 对询问合理排序,合并时把一棵树合并到另一棵树上并使得询问都能得到答案 (空间小) 。
- 每次合并新开节点,不需要离线 (空间大) 。
可持久化线段树 (主席树)
- 静态区间第 \(k\) 大
- 区间 \(mex\) (没有出现的最小自然数)
动态开点,每次单点操作最多只对 \(\lceil\log n\rceil\) 个节点有影响,于是新建 \(\lceil\log n\rceil\) 个节点进行维护。
时间复杂度:\(O(n\log n)\)
典例:
扫描线
- 求矩形面积并 / 周长并
面积并:先把所有横向边对 \(y\) 坐标排序,再把所有端点在 \(x\) 轴上进行离散化,对中间的所有线段开一棵线段树维护该线段内被整个图形所截的长度,扫描时进行维护。
周长并:
树链的并
- \(n\) 个点的树,给定 \(k\) 个点,求它们到根的边权并。
先按 DFS 序排序,答案即为:
虚树
- 给定一棵 \(n\) 个节点的树 \(T\),构造一棵新的树 \(T'\) 使其包含指定的 \(k\) 个节点和他们的 LCA,并使总节点数最小。
树链剖分
- 一个会让你代码长度增加 \(1kb\) 的数据结构。
分块
- 是一种暴力的优化。
对长度为 \(n\) 的序列分为 \(\sqrt n\) 个长度为 \(\sqrt n\) 的块,每一次操作只需分为整块的操作和单点的操作。
时间复杂度:\(O(n\sqrt n)\)
莫队
- 是一种基于分块的算法。
朴素莫队
- \(k\) 次询问,每次询问 \([l,r]\) 内的颜色个数。
适用范围:从 \([l,r]\) 到 \([l+1,r]\) 的转换比较快捷。
先对序列分块,再对所有询问按 \(l,r\) 排序,从一个询问到下一个询问只需要暴力拓展边界即可。
时间复杂度:\(O(n\sqrt n)\)
带修莫队
- 同上,但要支持单点修改。
对于修改的操作,实际上只是增加了一个时间轴,此时对于每次询问按 \(l,r,t\) 排序求解。
注意分块大小为 \(n^{\frac{2}{3}}\),总时间复杂度:\(O(n^{\frac{5}{3}})\)
回滚莫队
适用条件:区间转移时无法实现增加 / 删除。
笛卡尔树
- 一种特定的二叉数据结构。
- 具有堆的性质,满足父节点比儿子节点大。
- 这棵树的中序遍历就是原来的序列。
建树做法:单调栈维护右链,时间复杂度 \(O(n)\)
for(int i=1;i<=n;i++){
while(top&&a[st[top]]>=a[i])
ch[i][0]=st[top--];
if(top) ch[st[top][1]]=i;
st[++top]=i;
}
基环树
- \(n\) 个点,\(n\) 条边的连通图,环上的每个点ac都是其子树的树根。
- 对于有向图上的基环树,分为内向基环树和外向基环树。
二叉查找树 (Binary Search Tree)
- 中序遍历等同于原序列。
- 可以在某一位置插入,在 BST 上查找前驱后继。
Treap
- 堆和 BST 结合的平衡树。
- 旋转操作:在不改变原查找树的中序遍历下将一个节点向上翻转。
插入:在 BST 上寻找应该插入的位置 (类比线段树上二分) 。
删除:将所要删除的节点旋转到叶子再删除。
右旋:先将根的左儿子的右儿子连向根,再将根连向根的左儿子,最后重新维护所改变的节点。
左旋:先将根的右儿子的左儿子连向根,再将根连向根的右儿子,最后重新维护所改变的节点。
Splay
- 每次对一个点操作完成后要把这个点旋转到根节点的位置来保证复杂度。
插入:与 Treap 类似,找到合适的点插入后将其旋转到根。
删除:将根的左儿子的右儿子旋转到左边,再将根的右儿子连到根的左儿子右边,最后删除根。
双旋:每次用双旋将一个节点旋转到根的位置。
FHQ Treap (无旋 Treap)
- BST + Treap
最方便的平衡树 (STL)
std::set std::map
点分治
- 主要用来求解树上路径问题。
- 树上路径总数很多,但如果确定一个分治中心,然后将其子树内的路径合并就会变得很快。
- 怎么选分治中心 —— 就是树的重心。
- 选择树的重心后,分治下去的子树大小至少会变成原来的一半,所以最多会分治 \(\log n\) 层,总时间复杂度 \(O(n\log n)\)
边分治
原文地址:https://www.cnblogs.com/blueqwq/p/15019165.html
- 点击穿透原理及解决
- 如何使用Intellij搭建Spark开发环境
- 如何重置Cloudera Manager的admin密码
- 如何在CDH集群安装Anaconda&搭建Python私有源
- 如何使用Python Impyla客户端连接Hive和Impala
- 如何在Windows Server2008搭建DNS服务并配置泛域名解析
- 如何通过CM API优雅的获取元数据库密码
- CM启动报InnoDB engine not found分析
- 如何在Hue中使用Sentry
- 如何在Redhat中配置R环境
- 如何在Redhat中安装R的包及搭建R的私有源
- 什么是sparklyr
- 如何利用Dnsmasq构建小型集群的本地DNS服务器
- Cloudera Labs中的Phoenix
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux下Oracle如何导入导出dmp文件详解
- Linux中samba服务器的搭建教程
- linux环境搭建图数据库neo4j的讲解
- Linux编程之ICMP洪水攻击
- linux搭建squid代理服务器的完整步骤
- 使用wget递归镜像网站
- 整理Linux中字符串的相关操作技巧
- Ubuntu 16.04下无法安装.deb的解决方法
- 关于linux中系统输入输出的管理详解
- Linux下IP设置脚本的实例及遇到问题解决办法
- Linux与Windows文件互传(VMWare)
- 如何测试Linux下tcp最大连接数限制详解
- Linux中利用Vim对文件进行密码保护的方法详解
- Linux中禁止用户修改/重置密码
- 详解 MAC/Linux Vi配置环境变量及Java环境变量配置