可持久化线段树(主席树)
维护所有历史版本的线段树
维护每一个节点的左右儿子和权值。每一次修改时对于每一个访问的点建立一个新的节点,将这个节点修改后的权值和左右儿子填入新点内(本身权值不变)。

可持久化数组
等价于可持久化线段树
可持久化并查集
直接可持久化 parent 数组即可
可持久化平衡树
目前只有非旋 treap 支持可持久化
方式:类似主席树,对于每一个访问到的需要修改的点,新建一个点即可。
可持久化Trie
原理也同主席树类似,可持久化 01 trie 与可持久化线段树等价。
二维数点
这是主席树的一种经典应用。
只需要对每个x建立一个版本,保存这个x之前有多少点。然后在查询时查询rot[r]->query(x,y)-rot[l]->query(x,y)即可。
T1
题目
给定两个长度均为 $n$ 的 排列。
- $m$ 次询问。每次询问您要求出在第一个排列的 $[l_1,r_1]$ 和第二个排列的 $[l_2,r_2]$ 同时出现的数有多少个。
- $1\le n\le 10^6$,$1\le m\le 2\times 10^5$。强制在线。
思路
这个题一眼可能完全想不到什么可持久化。但是仔细一看,我们可以用每个数字的第一个数列和第二个数列出现位置组成一个坐标,然后使用刚才的二维数点即可。
代码
1 | /************************************************************** |
T2
题目
本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定。
魔力之都可以抽象成一个 $n$ 个节点、$m$ 条边的无向连通图(节点的编号从 $1$ 至 $n$)。我们依次用 $l,a$ 描述一条边的长度、海拔。
作为季风气候的代表城市,魔力之都时常有雨水相伴,因此道路积水总是不可避免的。由于整个城市的排水系统连通,因此有积水的边一定是海拔相对最低的一些边。我们用水位线来描述降雨的程度,它的意义是:所有海拔不超过水位线的边都是有积水的。
Yazid 是一名来自魔力之都的 OIer,刚参加完 ION2018 的他将踏上归程,回到他温暖的家。Yazid 的家恰好在魔力之都的 $1$ 号节点。对于接下来 $Q$ 天,每一天 Yazid 都会告诉你他的出发点 $v$ ,以及当天的水位线 $p$。
每一天,Yazid 在出发点都拥有一辆车。这辆车由于一些故障不能经过有积水的边。Yazid 可以在任意节点下车,这样接下来他就可以步行经过有积水的边。但车会被留在他下车的节点并不会再被使用。
需要特殊说明的是,第二天车会被重置,这意味着:
- 车会在新的出发点被准备好。
- Yazid 不能利用之前在某处停放的车。
Yazid 非常讨厌在雨天步行,因此他希望在完成回家这一目标的同时,最小化他步行经过的边的总长度。请你帮助 Yazid 进行计算。
本题的部分测试点将强制在线,具体细节请见【输入格式】和【子任务】。
为了方便你快速理解,我们在表格中使用了一些简单易懂的表述。在此,我们对这些内容作形式化的说明:
- 图形态:对于表格中该项为“一棵树”或“一条链”的测试点,保证 $m = n-1$。除此之外,这两类测试点分别满足如下限制:
- 一棵树:保证输入的图是一棵树,即保证边不会构成回路。
- 一条链:保证所有边满足 $u + 1 = v$。
- 海拔:对于表格中该项为“一种”的测试点,保证对于所有边有 $a = 1$。
- 强制在线:对于表格中该项为“是”的测试点,保证 $K = 1$;如果该项为“否”,则有 $K = 0$。
- 对于所有测试点,如果上述对应项为“不保证”,则对该项内容不作任何保证。
| $n$ | $m$ | $Q=$ | 测试点 | 形态 | 海拔 | 强制在线 |
|---|---|---|---|---|---|---|
| $\leq 1$ | $\leq 0$ | $0$ | 1 | 不保证 | 一种 | 否 |
| $\leq 6$ | $\leq 10$ | $10$ | 2 | 不保证 | 一种 | 否 |
| $\leq 50$ | $\leq 150$ | $100$ | 3 | 不保证 | 一种 | 否 |
| $\leq 100$ | $\leq 300$ | $200$ | 4 | 不保证 | 一种 | 否 |
| $\leq 1500$ | $\leq 4000$ | $2000$ | 5 | 不保证 | 一种 | 否 |
| $\leq 200000$ | $\leq 400000$ | $100000$ | 6 | 不保证 | 一种 | 否 |
| $\leq 1500$ | $=n-1$ | $2000$ | 7 | 一条链 | 不保证 | 否 |
| $\leq 1500$ | $=n-1$ | $2000$ | 8 | 一条链 | 不保证 | 否 |
| $\leq 1500$ | $=n-1$ | $2000$ | 9 | 一条链 | 不保证 | 否 |
| $\leq 200000$ | $=n-1$ | $100000$ | 10 | 一棵树 | 不保证 | 否 |
| $\leq 200000$ | $=n-1$ | $100000$ | 11 | 一棵树 | 不保证 | 是 |
| $\leq 200000$ | $\leq 400000$ | $100000$ | 12 | 不保证 | 不保证 | 否 |
| $\leq 200000$ | $\leq 400000$ | $100000$ | 13 | 不保证 | 不保证 | 否 |
| $\leq 200000$ | $\leq 400000$ | $100000$ | 14 | 不保证 | 不保证 | 否 |
| $\leq 1500$ | $\leq 4000$ | $2000$ | 15 | 不保证 | 不保证 | 是 |
| $\leq 1500$ | $\leq 4000$ | $2000$ | 16 | 不保证 | 不保证 | 是 |
| $\leq 200000$ | $\leq 400000$ | $100000$ | 17 | 不保证 | 不保证 | 是 |
| $\leq 200000$ | $\leq 400000$ | $100000$ | 18 | 不保证 | 不保证 | 是 |
| $\leq 200000$ | $\leq 400000$ | $400000$ | 19 | 不保证 | 不保证 | 是 |
| $\leq 200000$ | $\leq 400000$ | $400000$ | 20 | 不保证 | 不保证 | 是 |
思路
其实这个题挺显然的。
首先很明显,车虽然停在那里,但是并不会被重复使用,因为不会回到原处。我们能做的就只是把车开到离家尽量近的地方,然后走路回家。
所以我们只需要维护每个点的$dist$,然后并查集维护这个联通分量中能到达的$dist$最小的点的$dist$即可。
考虑先求出 $1$ 号点到其它每一个点的最短距离,设其为 $dist[x]$。
考虑对于每一个询问,如果保留海拔高于当前水位线的边,答案就是询问点所在的连通块内 $dist$ 最小值。
考虑当水位线逐渐降低时,可通行的边只加不减。于是考虑将所有边按照海拔从大到小的顺序依次加入,使用可持久化并查集维护连通关系和每个连通块 $dist$ 的最小值。
询问时直接二分当前访问哪个版本的并查集即可。
代码
1 |
|
T3
题目
小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。
小粽面前有 $n$ 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 $1$ 到 $n$。第 $i$ 种馅儿具有一个非负整数的属性值 $a_i$。每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子。小粽准备用这些馅儿来做出 $k$ 个粽子。
小粽的做法是:选两个整数数 $l$, $r$,满足 $1 \leqslant l \leqslant r \leqslant n$,将编号在 $[l, r]$ 范围内的所有馅儿混合做成一个粽子,所得的粽子的美味度为这些粽子的属性值的异或和。(异或就是我们常说的 xor 运算,即 C/C++ 中的 ˆ 运算符或 Pascal 中的 xor 运算符)
小粽想品尝不同口味的粽子,因此它不希望用同样的馅儿的集合做出一个以上的
粽子。
小粽希望她做出的所有粽子的美味度之和最大。请你帮她求出这个值吧!
思路
观察到价值是 $\bigoplus_{i=l}^r a_i$ ,我们可以定义 $s_i=\bigoplus_{j=1}^i a_j$ ,那么 $val[l,r]=s_{l-1}\oplus s_r$ 。特别的,有 $s_0=0$ 。这样,我们不同的 $i,j$ 满足 $0\le i\ne j\le n$ ,对应的就是不同的区间。
题目转化为给定一个长度为 $n+1$ 的数组 $s_i$ ,求 $i<j$ 时, $s_i\oplus s_j$ 的 $\frac {n(n+1)} 2$ 种取值中前 $k$ 大的值的和。
$i<j$ 这个条件很不美观,是一个上三角形的形状,我们交换 $i,j$ ,所求值也可以表示为 $i\ne j$ 时, $s_i\oplus s_j$ 的 $n(n+1)$ 种取值中前 $2k$ 大的值的和除以 $2$ 。由于 $i=j$ 时 $s_i\oplus s_j$ 的值为 $0$ ,而 $k\le \frac {n(n-1)} 2$ ,所以我们也可以忽略 $i\ne j$ 这个条件。
我们将 $s_i$ 的 $n+1$ 个值插入 01 Trie ,给定一个 $k$ ,我们可以在 $O(log_2 a)$ 的时间复杂度内找到与 $a$ 异或结果第 $k$ 大的值。方法类似于在线段树上二分。
我们维护一个大根堆,堆中初始时加入每个 $s_i$ 与 $s$ 中元素异或的最大值。每次我们取出堆顶,累加进答案,如果我们取出的是 $s_i$ 与 $s$ 中元素异或的第 $t$ 大值,就在堆中插入 $s_i$ 与 $s$ 中元素异或的第 $t+1$ 大值。这样进行 $k$ 次操作,取出的依次就是 $s$ 中元素两两异或的前 $k$ 大值。
令 $a=\max {a_i}$,则时间复杂度为 $O((n+k)\log_2 a\log_2 n)$ 。
代码
1 |
|
T4
题目
小 R 热衷于做黑暗料理,尤其是混合果汁。
商店里有 $n$ 种果汁,编号为 $0,1,\cdots,n-1$ 。$i$ 号果汁的美味度是 $d_i$,每升价格为 $p_i$。小 R 在制作混合果汁时,还有一些特殊的规定,即在一瓶混合果汁中,$i$ 号果汁最多只能添加 $l_i$ 升。
现在有 $m$ 个小朋友过来找小 R 要混合果汁喝,他们都希望小 R 用商店里的果汁制作成一瓶混合果汁。其中,第 $j$ 个小朋友希望他得到的混合果汁总价格不大于 $g_j$,体积不小于 $L_j$。在上述这些限制条件下,小朋友们还希望混合果汁的美味度尽可能地高,一瓶混合果汁的美味度等于所有参与混合的果汁的美味度的最小值。请你计算每个小朋友能喝到的最美味的混合果汁的美味度。
思路
考虑二分答案。
假设二分出的果汁最小美味值是 $m$,则我们只要考虑美味值 $d_i\geq m$ 的果汁即可。所以我们想到把果汁按照 $d_i$ 排序,这样每次就不用一个一个枚举。
接下来我们就要想怎么 $\mathrm{check}$ 就好了。贪心的想,我们就按照价格 $p_i$ 从小往大取,肯定是最优的。
所以关键问题是价格,再看数据范围,只够我们再加一个 $\mathrm{logn}$,那我们就能想到根据价格建立权值线段树,又因为我们要查询的都是区间,把它优化成主席树,就会方便许多。
现在,我们想如何按照我们的贪心思路在主席树上查询。假设我们现在在节点 $o$ 上,我们肯定优先先往左子树走,因为左子树对应的价格更小嘛。但我们还要保证果汁数量要 $\geq L$。所以,这个问题就有点类似于区间第 $k$ 小的问题。如果左子树中的果汁数量 $\gep L$,我们就去左子树找;反之,我们要取完左子树的所有果汁,并把剩下的果汁带到右子树中找就行了。
因此,我们在主席树中就要存两个信息。一是对应区间的果汁数量,而是对应区间果汁全取的价格。
最后,贪心取出的价格如果 $\leq g$,并且果汁数量 $\geq L$,就是合法的。
代码
1 |
|
T5
题目
印度尼西亚有 $N$ 个城市以及 $M$ 条双向道路,城市从 $0$ 到 $N - 1$ 编号,道路从 $0$ 到 $M - 1$ 编号。每条道路连接着两个不同的城市,第 $i$ 条道路连接第 $U[i]$ 个城市与第 $V[i]$ 个城市,汽车行驶这条道路将耗费 $W[i]$ 个单位汽油。通过这些道路,任意两个城
市间能够互相到达。
接下来的 $Q$ 天中, 每天会有一对城市希望建立政治关系。具体来说,第 $j$ 天,第 $X[j]$ 个城市想要和第 $Y[j]$ 个城市建立政治关系。为此,第 $X[j]$ 个城市将会派一名代表坐汽车前往第 $Y[j]$ 个城市。同样地,第 $Y[j]$ 个城市也会派一名代表坐汽车前往第 $X[j]$ 个城市。
为了避免拥塞,两辆车不应在任何时间点碰面。更具体地,两辆车不能在同一个时间点出现在同一个城市。同样地,两辆车也不应该沿相反的方向同时行驶过同一条道路。另外,汽车行驶过一条道路时必须完整经过道路并到达道路另一端的城市(换句话说,汽车不允许在道路中间掉转方向)。但是,汽车可以多次到达一个城市或是多次经过一条道路。此外,汽车可以在任何时间在任何城市等候。
由于高燃料容量汽车的价格昂贵,两个城市都分别希望选择一条路线,使得两辆汽车所需的最大单位汽油容量最小。每个城市中都有加油站并且供油量是无限的,因此汽车所需的单位汽油容量实际上就是行驶过的道路中最大的单位汽油消耗量。
你必须实现 init 和 getMinimumFuelCapacity 函数。
init(N, M, U, V, W)- 该函数将在所有getMinimumFuelCapacity的调用前被评测库恰好调用一次。- $N$: 一个整数表示城市数。
- $M$: 一个整数表示道路数。
- $U$: 一个长为 $M$ 的整数序列表示道路的第一个端点城市。
- $V$: 一个长为 $M$ 的整数序列表示道路的第二个端点城市。
- $W$: 一个长为 $M$ 的整数序列表示道路的汽油消耗。
getMinimumFuelCapacity(X, Y)- 该函数将被评测库调用恰好 $Q$ 次。- $X$: 一个整数表示第一个城市。
- $Y$: 一个整数表示第二个城市。
- 该函数必须返回一个整数,表示根据题目描述中的规则,两辆分别从第 $X$ 个城市与第 $Y$ 个城市出发要到达彼此城市的车,它们的单位汽油容量最大值的最小值。若无法满足题目规则则返回 $−1$。
思路
对于两点 $x,y$,$x,y$ 的最小瓶颈边权(也就是最大边最小的路的最大边权)等于 $x,y$ 的最近公共祖先(LCA)的点权。
对于本题来说,也可以理解为是查询两点间的瓶颈边,我们尝试运用类似 Kruskal 重构树的思想。
首先分析原题中的描述,可以知道:两点 $x,y$ 能互相派出使者访问,当且仅当两点连通,且它们所在的连通块不是一条链。
证明较为简单,连通性显然必须满足,而如果连通块是链也显然无解,尝试一下发现只要有度数 $\geq 3$ 的点或者环那么必定有解。
将边从小到大排序,运行和 Kruskal 算法类似的过程。不同的是,我们不仅要维护连通性,还要维护一个连通块究竟是不是链。发现一条链的性质很大程度上取决于两个端点,于是不妨在并查集的根节点处维护两个数组 $st_i,en_i$,如果该连通块是链,则存储链的端点。当一个连通块从链变成非链时,我们就在 Kruskal 重构树上新建一个节点,这个节点向所有链上的点连边;连通块合并同理。不难发现这样做仍然能保证原来 Kruskal 重构树的大部分性质,而且也能用 LCA 来处理在线询问。
简单来说,我们扫描每条边:
如果边两端已经连通:如果这个连通块是一条链,那么加上这条边显然不再是链了,那么打上标记,同时在 Kruskal 重构树上连边;否则没有变化。
如果没有连通:
如果原来两个连通块有至少一个不是链,那么新连通块也一定不是链;
如果原来两个连通块都是链,那么新连通块是不是链取决于连边是不是在端点之间进行的。也可简单维护。
注意我们由于要维护一个点所在的连通块,且要支持合并,应采用启发式合并,使时间复杂度稳定在 $O(n\log n)$。
总时间复杂度 $O((n+q)\log n)$。
代码
1 |
|
T6
题目
There is a tree with $N$ nodes, whose root is 1.
There are $Q$ queries for you,for each query,we will give $K$ numbers,which are $A_1,A_2,\dots,A_K$.
For every node $x\in[1,N]$ in the tree,we assume it’s good if there is not a node $y\in A$,such that $y$ is the ancient of $x$ or $y=x$
And we will give two numbers $T , P$ to show the property of each query.
1.when $T=1$,you should output the sum of the distance between every good node and $P$.
2.when $T=2$,you should output the minimum distance between every good node and $P$.
3.when $T=3$,you should output the maximum distance between every good node and $P$.
Let the distance between nodes in the tree be the shortest path between these two nodes.And we assume the length of each edge is 1.
Specially,the distance between two same nodes is 0.
For each query,if there is no nodes that is good,just output -1.









