Has Not Appeared
 0/5

Virtual Tree

Author: Ryan Fu

Compressing a tree to only the necessary nodes.

Often, when running operations or dynamic programming on trees, we only need to keep track of a few key nodes and their relationships. If we are able to isolate the few relevant nodes that keep the structure of the tree intact, while still maintaining the relationships between key nodes, we can cut our time complexity down significantly.

Example - Leaf Color

Focus Problem – try your best to solve this problem before continuing!

Naive Solution

We can sum the number of vertex sets TT that satisfy the condition with degree 11 vertices having color cc across all c[1,N]c \in [1,N] to obtain an answer.

We define dp[v]\texttt{dp}[v] to be the number of induced subgraphs that are trees rooted at vv such that all leaves have color cc. When transitioning, initialize dp[v]=1\texttt{dp}[v] = 1. Transitions are as follows:

  • For every child uu of vv, we can either attach one of the induced subgraphs that are trees containing uu or ignore uu completely:

    dp[v]=dp[v](1+dp[u])\texttt{dp}[v] = \texttt{dp}[v] \cdot (1 + \texttt{dp}[u])
  • However, if avca_v \neq c, then we have to remove the case where the induced subgraph is just vv itself, because this violates the condition:

    dp[v]=dp[v]1\texttt{dp}[v] = \texttt{dp}[v] - 1

To extract our answer, we can iterate over every possible root rr of our induced subgraph.

  • If ar=ca_r =c, then we can directly add dp[v]\texttt{dp}[v] to our answer.
  • Otherwise, we need to make sure that rr is not degree 11 in any of the induced subgraphs we add. Thus, we subtract all the cases when rr is attached to exactly one of its children.

Thus, our answer will be

ar=cdp[r]+arc(dp[r]sChildren(r)dp[s]).\sum_{a_r = c} \texttt{dp}[r] + \sum_{a_r \neq c} \left( \texttt{dp[r]} - \sum_{s \in \text{Children}(r)} \texttt{dp[s]} \right).

The time complexity for this approach is O(n2)\mathcal{O}(n^2), because for each color, we iterate over all nn nodes.

Here is a (TLE) code that demonstrates this approach:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int MAX_N = 2e5 + 1;
constexpr int MOD = 998244353;
int n, a[MAX_N];
ll dp[MAX_N], ans;

Virtual Tree Optimization

To accelerate our dynamic programming approach, we can observe that our dynamic programming transitions are relatively simple when involving certain types of nodes.

The most simple case of this is when a node vv has no nodes of color cc in its subtree. Here, we can simply conclude dp[v]=0\texttt{dp[v]}=0, because it is impossible to construct an induced subgraph in the subtree of vv with leaves of color cc.

Another case of simple transitions is when only one child uu of vv has any nodes of color cc. Then, from our previously established dp transitions, we observe that dp[v]\texttt{dp}[v] is equivalent to dp[u]\texttt{dp}[u].

Let SS be the set of nodes excluding these two cases. More formally, if we let Sc={vVav=c}S_c = \{ v \in V \mid a_v = c \}, then

S=Sc{LCA(u,v)u,vSc}.S = S_c \cup \{\text{LCA}(u,v) \mid u, v \in S_c\}.

We define SS to be the virtual tree or auxillary tree of ScS_c. We can also define pvp'_v, the virtual parent of vv as the lowest node in SS such that pvvp'_v \neq v and LCA(pv,v)=pv\text{LCA}(p'_v,v) = p'_v, and vv as a virtual child of pvp'_v.

Here is an example of a virtual tree, with nodes in ScS_c colored purple, and the rest of the virtual tree in blue:

VTree

From here, we can calculate our dp values similarly to before, except we only process nodes in SS, and we consider virtual children instead of direct children.

Notice that when calculating our answer, we also only need to consider nodes in SS. Nodes not in SS can not be the root because only one of their children have nodes of color cc in their subtree, meaning that we will end up with a degree 11 node not of color cc.

Thus, our time complexity will be O(cS)\mathcal{O}(\sum_c |S|), since we iterate over the set SS for each distinct color.

In the following section, we prove that S|S| is bounded by O(Sc)\mathcal{O}(S_c), and also demonstrate how to construct a virtual tree.

Virtual Tree Construction

A well-known method to construct the virtual tree of set S0S_0 is as follows:

  • Sort the points in S0S_0 by DFS order, and add them to SS
  • Calculate the LCA of any two adjacent key points in S0S_0, and add that to SS
  • Build the virtual tree based on the ancestor-descendant relationship of the original tree

For a rough proof of correctness, consider the following:

Observe that a vertex vSv \in S must either satisfy vS0v \in S_0 or there exist at least two distinct children of vv with key points in their subtrees.

The former is taken care of immediately in step 1. In the latter case, as a property of DFS order, there must exist key points a,ba,b in the subtree of vv such that a,ba,b are in distinct subtrees and a,ba,b are adjacent in the DFS order when only considering key points. Because vv is LCA(a,b)\text{LCA}(a,b), our construction neccesarily holds true. A corollary of our construction is that S|S| is indeed bounded by O(S0)\mathcal{O}(|S_0|) - in fact, a tight bound is S2S01|S| \leq 2 \cdot |S_0|-1.

Implementation

Below is an implementation for the task, which also contains general code for constructing virtual trees. Because cS\sum_c |S| is O(n)\mathcal{O(n)}, and we sort by DFS order, our final time complexity is O(nlogn)\mathcal{O}(n\log n).

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int MAX_N = 2e5 + 1;
constexpr int LG = 18;
constexpr int MOD = 998244353;
int n, a[MAX_N];

Problems

Warning!

Note that Bridges: The Final Battle requires concepts from Offline Deletion and BCCs and 2CCs to solve.

StatusSourceProblem NameDifficultyTags
GymNormal
Show TagsVirtual Tree
CFHard
Show TagsVirtual Tree
CFHard
Show TagsVirtual Tree
GymInsane
Show TagsBlock Cut Tree, Virtual Tree

Module Progress:

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!