Files
cpp-oi-notes/2.数据结构/数据结构.md
T
2024-09-19 21:08:58 +08:00

216 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 数据结构
- [数据结构](#数据结构)
- [单调队列](#单调队列)
- [单调队列引入](#单调队列引入)
- [引入问题滑动窗口](#引入问题滑动窗口)
- [单调队列例题](#单调队列例题)
- [P1714 切蛋糕](#p1714-切蛋糕)
- [P1714题解](#p1714题解)
- [单调栈](#单调栈)
- [并查集](#并查集)
- [并查集基础](#并查集基础)
- [并查集查询](#并查集查询)
- [并查集合并](#并查集合并)
- [带权并查集](#带权并查集)
- [带权并查集例题](#带权并查集例题)
- [P2024 NOI2001食物链](#p2024-noi2001食物链)
- [P2024题解](#p2024题解)
- [可撤销并查集](#可撤销并查集)
- [并查集例题](#并查集例题)
- [并查集例题1](#并查集例题1)
- [并查集例题1题解](#并查集例题1题解)
- [并查集例题2](#并查集例题2)
- [并查集例题2题解](#并查集例题2题解)
- [并查集例题3](#并查集例题3)
- [并查集例题3题解](#并查集例题3题解)
- [](#堆)
- [线段树](#线段树)
- [树状数组](#树状数组)
- [Trie](#trie)
## 单调队列
### 单调队列引入
#### 引入问题滑动窗口
> 如果有人比你小还比你强,那你就没有任何用了 —— noip
有 $n$ 个 oier ,每个 oier 有成绩和考试,保证给定数据中 oier 的出生年份单调,求每 $k$ 个年份时这 $n$ 个 oier 的最大成绩。
伪代码:
```cpp
deque<pair<int,int>> q; // 成绩,年份
while(!q.empty() && newgrade>q.back()) q.pop_back;
q.push_back(newgrade,newyear);
while(q.front().second要退役){
q.pop_front();
}
最大值q.front().first
```
时间复杂度 $O(n)$ (均摊复杂度,可能某次while执行很久,可能某次很快)
### 单调队列例题
#### P1714 切蛋糕
[题目链接](https://www.luogu.com.cn/problem/P1714)
有一个长方形的蛋糕,被不同的色彩分成了 $N$ 个相同的小块,每个小块有着对应的幸运值。
小 Z 作为寿星,希望吃到的蛋糕的幸运值最大,但是他最多只能吃 $M (M \le N)$
你需要在这 $N$ 小块蛋糕中找出连续的几块,使得其上总幸运值最大。
形式化地,在数列 ${p_n}$ 中,找出一个长度小于 $M$ 的子段 $[l, r]$,最大化 $\sum^{r}_{i - l} {p_i}$
$1 \le n \le 5 \times 10^5$
##### P1714题解
---
## 单调栈
---
## 并查集
### 并查集基础
基础操作:合并、查询
#### 并查集查询
对于给定的 $a$,沿着树向上移动知道根节点即可
在合并的过程中的每个节点都属于这个集合,所以将父亲节点直接设为根即可。
#### 并查集合并
合并两个集合时,可以将一个集合的根节点设为另一个集合的根节点。
为了防止退化,可以将节点较少或深度较小的一棵树连接到令一颗上。
### 带权并查集
我们可以在并查集的边上维护某种值,在路径压缩时产生运算。
#### 带权并查集例题
##### P2024 NOI2001食物链
[题目链接](https://www.luogu.com.cn/problem/P2024)
动物王国中有三类动物 $A,B,C$,这三类动物的食物链构成了有趣的环形。$A$ 吃 $B$$B$ 吃 $C$$C$ 吃 $A$。
现有 $N$ 个动物,以 $1 \sim N$ 编号。每个动物都是 $A,B,C$ 中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这 $N$ 个动物所构成的食物链关系进行描述:
- 第一种说法是 `1 X Y`,表示 $X$ 和 $Y$ 是同类。
- 第二种说法是`2 X Y`,表示 $X$ 吃 $Y$。
此人对 $N$ 个动物,用上述两种说法,一句接一句地说出 $K$ 句话,这 $K$ 句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
- 当前的话与前面的某些真的话冲突,就是假话;
- 当前的话中 $X$ 或 $Y$ 比 $N$ 大,就是假话;
- 当前的话表示 $X$ 吃 $X$,就是假话。
你的任务是根据给定的 $N$ 和 $K$ 句话,输出假话的总数。
###### P2024题解
考虑维护带权并查集,对每次给定的话进行查询与合并。
具体的,对于并查集中的每两个节点,使用 $0$ 表示互为同类, $1$ 表示父亲吃儿子, $2$ 表示儿子吃父亲。
对于每句话 `1/2 X Y`,查询 $X, Y$ 之间的关系,若无冲突便合并即可,注意路径压缩时的运算。
![alt text](image.png)
### 可撤销并查集
对于一开始相互独立的 $n$ 个点,维护以下两种操作共 $q$ 次:
1. 给定 $a, b$ 两个点,判断是否在同一个联通块中,如不在则在 $a, b$ 间连边。
2. 撤销最后的若干次操作 $1$
要求复杂度 $O(q \log n)$
考虑用栈记录最近操作 $fa_x \leftarrow y$ ,每次撤销弹出栈顶,并将 $fa_x \leftarrow x$
因为要保证可逆,所以不能路径压缩,只能启发式合并。
### 并查集例题
#### 并查集例题1
有 $n$ 个点,初始时均为孤立点。
接下来有 $m$ 次连边操作,第 $i$ 次在 $a_i, b_i$ 之间连一条边。
接下来有 $q$ 次询问,每次询问两个点在第几次加边操作联通。
$1 \le n, m, q \le 10^5$
##### 并查集例题1题解
考虑对于每一次合并的 $a_i, b_i$,若两个点不联通,则在另外一颗树中连接 $a_i, b_i$,边权为 $i$。
每次查询就是在令一颗树中找到 $u, v$ 路径上边权最大值,可以使用树上倍增维护。
#### 并查集例题2
有一个长度为 $n$ 的 $01$ 序列 $a_1, \dots, a_n$,一开始全是 $0$。接下来进行如下 $m$ 次操作:
- $a_x \leftarrow 1$
- 输出 $\min\{x \in [l,r], a_x = 0\}$
$1 \le n, m \le 10^6$
##### 并查集例题2题解
建立并查集,使得 $i$ 所在联通块的根节点为 $i$ 后面第一次出现 $0$ 的位置,初始 $f_i = i$
对于每一次 $a_x \leftarrow 1$,如果 $a_x$ 原先不为 $1$,则令 $f_x = f_{x - 1}$
每次查询输出 $x$ 的祖先。
#### 并查集例题3
给定一颗 $n$ 个节点的树,接下来有 $m$ 次操作:
- 加一条 $a_i$ 到 $b_i$ 的边。
- 询问两个点之间是否存在至少两条**边不相交**的路径。
**边不相交:指的是两个路径没有公共边。**
$1 \le n, m \le 10^6$
##### 并查集例题3题解
前置知识:[强联通分量](../树上问题,图论/树上问题,图论.md#强联通分量)
---
## 堆
---
## 线段树
---
## 树状数组
---
## Trie
---