6.4 KiB
数据结构
单调队列
单调队列引入
引入问题滑动窗口
如果有人比你小还比你强,那你就没有任何用了 —— noip
有 n 个 oier ,每个 oier 有成绩和考试,保证给定数据中 oier 的出生年份单调,求每 k 个年份时这 n 个 oier 的最大成绩。
伪代码:
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 切蛋糕
有一个长方形的蛋糕,被不同的色彩分成了 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食物链
动物王国中有三类动物 $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 之间的关系,若无冲突便合并即可,注意路径压缩时的运算。
可撤销并查集
对于一开始相互独立的 n 个点,维护以下两种操作共 q 次:
- 给定
a, b两个点,判断是否在同一个联通块中,如不在则在a, b间连边。 - 撤销最后的若干次操作
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题解
前置知识:强联通分量
