AtCoder - Subtree

Authors: Benjamin Qi, Andi Qu

Solving for One Root

Let's consider a simpler problem - assuming that node 1 is painted black, how many ways can we paint the tree?

First, root the tree at node 1.

Let dp[i]dp[i] be the number of ways that we can paint the subtree of node ii if we know that node ii is painted black. (1 if node ii is a leaf)

For each child cc of ii, there are dp[c]+1dp[c] + 1 ways to paint its subtree if ii is painted black.

This means that we have the recurrence

dp[i]=cChildren of i(dp[c]+1)dp[i] = \prod_{c \in \text{Children of } i} (dp[c] + 1)

The answer to the simpler problem is thus dp[1]dp[1].

Finding all dp[i]dp[i] takes O(N)O(N) time.

Solving for all roots

First, root the tree arbitrarily and do a DFS to find all dp[i]dp[i].

Let dp2[i]dp2[i] be the number of ways to colour the tree if we remove node ii's subtree excluding node ii from the graph and we know that node ii is painted black. (1 if node ii is the root)

The number of ways to paint the tree if we know node ii is black is simply dp[i]dp2[i]dp[i] \cdot dp2[i].

How can we find dp2[i]dp2[i] efficiently though?

The basic recurrence for computing dp2[i]dp2[i] is

dp2[i]=(dp2[Parent of i]+1)sSiblings of i(dp[s]+1)dp2[i] = (dp2[\text{Parent of } i] + 1) \cdot \prod_{s \in \text{Siblings of } i} (dp[s] + 1)

Since MM isn't guaranteed to be prime though, we can't just find the product of each node's children and divide that product by each of its children's dp[i]dp[i]. (Since we can't find modular inverses easily.)

However, notice how if node ii is the kk-th child of its parent, then we can use prefix and suffix products to compute

sSiblings of i(dp[s]+1)\prod_{s \in \text{Siblings of } i} (dp[s] + 1)

without using division. (i.e. We find the product of dp[s]+1dp[s] + 1 for the first to the (k1)(k - 1)-th child of ii's parent, the product of dp[s]+1dp[s] + 1 for the (k+1)(k + 1)-th to the last child of ii's parent, and then multiply those together.)

Finding all dp2[i]dp2[i] takes O(N)O(N) time using a DFS, so the total complexity of this algorithm is thus O(N)O(N).

Code

down corresponds to dpdp and up corresponds to dp2dp2.

/**
* Description: modular arithmetic operations
*/
template<int MOD, int RT> struct mint {
static const int mod = MOD;
static constexpr mint rt() { return RT; } // primitive root for FFT
int v; explicit operator int() const { return v; } // explicit -> don't silently convert to int
mint() { v = 0; }
mint(ll _v) { v = (-MOD < _v && _v < MOD) ? _v : _v % MOD;

Give Us Feedback on AtCoder - Subtree!