Эту проблему можно решить с помощью динамического программирования на деревьях, о ней вы можете прочитать здесь https://www.geeksforgeeks.org/dynamic-programming-trees-set-2/.
Давайте разделим задачу на две части, первая - найти количество допустимых путейв поддереве узла u
.Вторая часть состоит в том, чтобы найти ответ для узла u
, если мы не рассматриваем его поддерево, а обращаемся к его родителю и т. Д.
Давайте рассмотрим 1 как корень дерева.
Теперь для решения первой части мы создадим массив in[]
, в котором мы будем хранить количество путей в поддереве узла u
, поэтому in[u]
будет представлять количество допустимых путей, начиная сузел u
и посещение его поддерева.Чтобы вычислить этот массив, мы можем запустить простой dfs следующим образом:
//u is the current node - p is the parent
void dfs1(int u, int p) {
for (int i = 0; i < g[u].size(); i++) { //iterate through the adjacency of node u
int v = g[u][i]; // v is the child of u
if (v != p) { //in case v is the parent just ignore it
dfs1(v, u); //go to node v
if (u >= k && v >= k) { //if value of u or v is less than k then we cant start at this node so it should be 0
in[u] += in[v] + 1; //add to number of paths of u the number of paths starting from the node v + 1 (+1 because we can also go from u to v)
}
}
}
}
Для решения второй части нам нужен массив out[]
, где out[u]
- это число путей, которые действительны, если мы нерассмотрим поддерево u
, которое идет к родителю u
и так далее.
Давайте позвоним родителю u
P[u]
.Для вычисления out[u]
мы будем полагаться на p[u]
.out[i]
- это число допустимых путей, если мы перейдем к p[u]
, и что мы можем сделать, когда достигнем p[u]
, это либо пройти через его поддерево (исключая, конечно, u
) или посетить p[p[u]]
(родительский элемент для u
), поэтому out[u]
равен (out[p[u]] + 1) + (in[p[u]] - in[u] - 1)
.
// u is the current node - p is the parent
void dfs2(int u, int p) {
for (int i = 0; i < g[u].size(); i++) { // iterate through the adjacency of node u
int v = g[u][i]; // v is the child of u
if (v != p) { // in case v is the parent just ignore it
if (v >= k && u >= k) { // if value of u or v is less than k then we cant start at this node so it should be 0
out[v] += (out[u] + 1); //add to the number of paths of v the number of paths from it's parent (u) + 1 if we dont use the subtree of u
out[v] += (in[u] - in[v] - 1); // add to the number of paths of v the number of paths from it's parent (u)
// we should subtract in[v] + 1 because we want to exclude this branch from the subtree of the parent
}
dfs2(v, u); // go to node v
}
}
}
Чтобы найти ответ, просто сложите все out[u] + in[u]
для всех узлов и разделите на 2, потому что каждый путь был вычислендважды.
сложность O (V + E)