一、DFS 序
DFS 序是指:每个节点进出栈的时间序列。
例如:对上面这棵树,其 DFS 序列是:
它是这样被列写出来的:从顶点 A 出发,A 有子节点 B 和 C ,先访问 B ;B 有子节点 E ,访问 E ;E无子节点,退出(序列上也要再添加一个 E ),访问 F ;F 有子节点 K ,访问 K ;K 无子节点,退出;……
就完成了 DFS 序的列写。
但是有时候我们并不需要将 DFS 过程中退出某个节点的次序也记录下来,只需记录访问各节点的先后顺序。我们来看 CodeForces 1006E:
有一个多叉树,根节点编号为 1 ,代表 Berland 军队中的最高指挥官。其余节点依次编号2、3、4、……,分别代表2、3、4、……号军官。每个节点的父节点是其直接上级,每个节点的子节点代表其下属。
输入第一行为 n 和 q ,代表节点数和询问次数。接下来一行包含 n-1 个数 p2、p3、……、pn ,意思是:pi 是 i 的直接上级。
接下来 q 行,每行 2 个数 u 、p ,分别代表下命令的军官和第 p 个收到命令的军官。发送命令的先后顺序是 DFS 决定的。例如:
If officer 1 spreads a command, officers receive it in the following order: [1,2,3,5,6,8,7,9,4].
If officer 3 spreads a command, officers receive it in the following order: [3,5,6,8,7,9].
If officer 7 spreads a command, officers receive it in the following order: [7,9].
If officer 9 spreads a command, officers receive it in the following order: [9].
对每个询问:
u p
输出第 p 个收到命令的军官的编号。其中 2 ≤ n, q ≤ 200000 。
解 显然这题是模板题,各军官发送命令的先后顺序在图上完全符合 DFS 序。因此直接套用前面提供的 DFS 模板 即可。
但是这棵多叉树可以有 200000 个节点,询问也可以有 200000 次。如果我们对每个询问都在这么大一张图进行一次 DFS ,一定会超时超到你哭天喊地。所以我们尝试借鉴莫队的思想,先将询问一次录入,然后排序,如果是同一个指挥官发送命令,就只需要一次 DFS 。
代码:
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<bitset>
#include<map>
#include<vector>
#pragma warning(disable:4996)
using namespace std;
struct Edge {
unsigned NextStoPos = 0, to = 0; };
Edge e[2000000]; unsigned head[200001], u, v; bitset<200001> b; vector<unsigned> o; vector<pair<unsigned, unsigned>> Q, R;
map<pair<unsigned, unsigned>, unsigned> A;
const unsigned Init_RevIdx = 0; pair<unsigned, unsigned> p;
inline void AddEdge(unsigned* RevIdx, Edge* Edge, const unsigned& vtx_u, const unsigned& vtx_v, unsigned& Idx_of_Sto) {
Edge[Idx_of_Sto].to = vtx_v; Edge[Idx_of_Sto].NextStoPos = RevIdx[vtx_u];
RevIdx[vtx_u] = Idx_of_Sto;
}
template<size_t n> inline void DFS_PrtSeq(const unsigned& vertex, vector<unsigned>& OutSeq, const unsigned