dfs序 括号序 欧拉序 树上莫队 虚树建立 傻傻分不清

括号序

进加一次,出加一次,显然最后得到的序列只有 \(2n\) 个点。

void dfs(int x) {
	in[x]=++tot;
	for(y) dfs(y);
	out[x]=++tot;
}

image

image

显然我们希求将树上路径表示为区间,然后用莫队抑或是其它数据结构维护。

对于 \(y\in T_x\) 的情况就是上图,我们发现只要取 \([in_x,in_y]\) 即可达到只有路径上的点被加了一次,其他要么没加要么加 \(2\) 次。因此,我们只保留加 \(1\) 次的点。也就是说每次更新一个点就取反它的是否加入状态。

image

否则,显然我们取 \([out_x,in_y]\),再补上 \(LCA\) 的贡献即可。

欧拉序

用来求 LCA 以及求的方式能够证明某些结论。

void dfs(int x) {
	id[x]=++tot; v[tot]=x;
	for(y) {
		dfs(y);
		v[++tot]=x;
	}
}

我们可以猜想 \(x,y\) 的 LCA 就是 \(v[id_x,id_y]\) 深度最浅的点。

下文假定 \(id_x<id_y\)/

不难发现命题等价于记 \(LCA(x,y)=d\)\(d\) 的祖先不在区间内,\(d\) 的兄弟不在区间内,\(d\) 出现在区间内。

考虑 \(id_{fa_d}<id_x<id_y\) ,且要再次出现 \(fa_d\) 要等到 \(d\) 回溯完后才出现。所以一定不会出现。

考虑在 \(d\) 之前遍历的兄弟无影响(因为要之前的遍历完才可能遍历到 \(d\)),之后的不会在区间取到,因为要 \(d\) 回溯上去再遍历兄弟,所以兄弟不在区间内。

\(d=x\),显然正确。因为显然 \([id_x,id_y]\) 都在 \(x\) 子树内。最浅的一定是 \(x\)

若不是,则 \(x,y\) 分居 \(d\) 的不同子树,那么要实现不同子树的遍历一定需要回溯到 \(d\) 再遍历下去,所以一定存在 \(d\)

综上,这样是对滴。

多点 LCA 结论!

考虑点按 \(dfs\) 序升序排列,又因为 \(LCA\) 具有可并性,相邻的并一下就好了。

考虑 \(ST\) 表求 \(LCA\) 的过程,发现若干个小区间并起来显然是大区间的。所以求 \(dfs\) 序最小的和最大的的 \(LCA\) 即可。

虚树

显然,虚树的形态与根的选取有关/fn,见 https://ac.nowcoder.com/acm/contest/40647/C

https://www.luogu.com.cn/blog/Rainbowsjy/fou-xu-yao-nao-zi-di-jian-xu-shu

里面有一个结论。

为啥要按 dfs 序排列然后取相邻的 LCA?这一步是不是等价于求两两之间的 LCA?

考虑若 \(dfn_x<dfn_y\) 则上文的欧拉序也有 \(id_x<id_y\)

考虑若 \(dfn_x<dfn_y<dfn_z\),那么 \(LCA(x,z)=[id_x,id_z]\),显然 LCA 要么出现在 \([id_x,id_y]\) 要么出现在 \([id_y,id_z]\),所以相邻的取一下一定可以取到。

类比到多个点的情况,不难发现则将大区间划分成若干个相邻点的小区间。

那么解决完两两 LCA 之后,是不是要根据祖先后代关系建边。

tips:俺经常在想会不会求完 LCA 之后导致 LCA 的 LCA 没有在关键点中。但实际上两两求是不会的。考虑反证,若存在 \(d_1,d_2\) 满足 \(d_1\)\(x_1,y_1\) 的 LCA,\(d_2\) 同理,那么按理说不存在 \(D\),满足 \(LCA(d_1,d_2)=D\),且存在两个原先的关键点的 LCA 为 \(D\),但显然考虑 LNOI LCA 那道题,\(y_1,x_2\) 的 LCA 一定是 \(d_1,d_2\) 的 LCA。。。所以这样两两 LCA 是正确的!

也就是说只有 1 个求出来后的 LCA,满足深度最小,且囊括了所有关键点。

一种方法是增量法:https://www.cnblogs.com/alex-wei/p/Tree_Tree_Tree_Tree_Tree_Tree_Tree_Tree_Tree_Tree_Tree_Tree_Tree_Tree_Tree.html

但是太麻烦了!!!!!!

考虑我们求出所有关键点后,如何构造一棵树。

是不是 dfs?然后父子连边。

但显然我们不可能 dfs,但不难发现虚树上的 dfs 序的相对大小关系跟原树的 dfs 序的相对大小关系是等价的。

于是,我们只要按 dfs 序升序排,无非就剩 2 种情况。

  1. \(x,y\) 在原树上是自上而下的关系,直接连边。

  2. \(LCA(x,y)\)\(x,y\) 分在 2 棵子树。因为它们 dfs 序相邻,所以一定是 \(x\) 是虚树的叶子,y 要直接连 \(LCA\to y\)

综上,我们只需要连 \(LCA\to y\) 的边,且根据我们的 tips,不难发现对于连边到的点显然都是处理后的关键点(1 情况显然,2 情况根据 tips,发现 \(x,y\) 无论原先关键点,还是新增的,其 \(LCA\) 一定也是关键点)。

posted @ 2022-08-13 18:11  FxorG  阅读(190)  评论(0编辑  收藏  举报