虚树(Virtual Tree)学习笔记
一、基本概念
虚树是一种用于处理树上复杂问题的简化数据结构,通过保留关键节点(如查询点、LCA等)及其间的必要路径,将原树的规模从O(n)压缩至O(k)(k为关键节点数量),从而优化算法效率1。
二、构造步骤
- 选取关键节点 :根据问题需求确定需要保留的节点集合S。
- 排序与插入LCA :将S中的节点按DFS序排序,依次计算相邻节点的LCA并加入集合(避免遗漏路径)。
- 栈维护虚树结构 :使用栈模拟构造过程,每次处理新节点时弹出栈顶至当前节点的祖先,连接父子关系,最终形成仅包含关键节点和必要LCA的虚树1。
三、核心性质
- 虚树的节点数不超过2k-1(k为初始关键节点数)。
- 虚树中任意两节点的路径与原树中路径完全一致。
四、应用场景
- 树上路径查询 :如多次询问不同节点对的路径信息,通过虚树减少重复计算。
- 树形DP优化 :将原树DP转移限制在虚树的关键节点上,降低时间复杂度1。
五、示例说明
例如,处理多组树上的最近公共祖先查询时,可先将所有查询涉及的节点作为关键节点构造虚树,再在虚树上进行集中处理,避免对原树的多次遍历。
六、经典例题与代码实现
例题1:Bzoj2286 [Sdoi2011]消防(虚树+树形DP)
问题描述
给定一棵带权树,多次询问关键点集合(资源丰富的节点),要求切断若干边,使得根节点(1号)无法到达任何关键点。切断边的代价为边权,求最小总代价1。
解法思路
- 原树DP的瓶颈 :直接对原树进行树形DP的时间复杂度为O(nm)(n为总节点数,m为询问次数),当n和m较大时无法通过。
- 虚树优化 :仅保留关键点及其LCA,构建虚树后在虚树上进行DP,时间复杂度降至O(∑k)(k为单次询问关键点数量)。
关键步骤
- 构建虚树 :将关键点按DFS序排序,用栈维护虚树结构,连接必要的LCA节点。
- 虚树DP :定义
dp[u]为断开u到其子树内所有关键点的最小代价。转移时:
- 若子节点是关键点,必须断开当前边(代价为边权);
- 若子节点非关键点,选择断开当前边或继承子节点的最小代价2。
虚树构建与DP代码示例(C++)
// 虚树构建核心代码(基于DFS序和栈)
vector<int> key_nodes; // 关键点集合
sort(key_nodes.begin(), key_nodes.end(), [&](int a, int b) { return dfn[a] < dfn[b]; });
stack<int> st; st.push(1); // 根节点入栈
vector<int> vt_edges[MAXN]; // 虚树边
for (int u : key_nodes) {
int lca = get_lca(u, st.top());
while (st.size() > 1 && dfn[st.top()] > dfn[lca]) {
int top = st.top(); st.pop();
if (dfn[st.top()] < dfn[lca]) vt_edges[lca].push_back(top);
else vt_edges[st.top()].push_back(top);
}
if (st.top() != lca) { vt_edges[lca].push_back(st.top()); st.pop(); st.push(lca); }
st.push(u);
}
// 剩余节点出栈连接
while (st.size() > 1) {
int top = st.top(); st.pop();
vt_edges[st.top()].push_back(top);
}
// 虚树DP代码
int dp[MAXN];
void dfs(int u, int fa) {
dp[u] = 0;
for (int v : vt_edges[u]) {
if (v == fa) continue;
dfs(v, u);
if (is_key[v]) dp[u] += edge_weight[u][v]; // 子节点是关键点,必须断边
else dp[u] += min(edge_weight[u][v], dp[v]); // 非关键点,取断边或子节点DP值
}
}
例题2:Luogu P4775 NOI2018 情报中心(虚树+链交处理)
问题描述
给定带权树和m条链(每条链有花费),求两条有边交的链的最大价值(链并边权和-两链花费)3。
解法思路
- 虚树应用 :将链的端点作为关键点构建虚树,快速处理链交关系。
- 链拆分 :将任意链拆分为两条直上直下的链(从LCA到两端点),利用虚树结构统计边交。
七、总结
虚树通过保留关键节点和必要LCA,将原树规模压缩至O(k),适用于多组询问、关键点稀疏的场景。结合树形DP或链交处理,可显著优化时间复杂度。
备注:学习内容来自OI Wiki

浙公网安备 33010602011771号