1039D Test Instructions:
Give you a tree that requires a given chain that is longer than k = 1, 2, 3, ..., n, to find the largest chain of splits.
1059E Test Instructions:
I'll give you a tree with weights. For a given set of L, W to find the smallest complete vertical chain to meet the number of points per chain not exceeding L, weights and not exceeding W.
It is obvious that the two questions have common ground, that is, let us seek to satisfy certain conditions of the tree's most value chain.
Compared to violent can try to use DP count, but I do not want to go deep dp, because the equation is more complex, not easy to think about.
Coincidentally, these two questions can be done with similar greedy thoughts.
Before thinking about specific details, you need to be clear about the main idea of greed: in the process of backtracking from the bottom up, always greedy to chain under the right conditions.
1039D
If the given K-value can be solved quickly, it is possible to use the idea of chunking to deal with the case of K difference.
How to solve a given k?
It's still a greedy way.
In the case of Dfs backtracking, once the current point can be chained, it is settled directly in Chin:)
The specific operation process, the need for each point record longest and the second eldest son chain, so once the two and reached K, it can be chained.
The
proves slightly.
#include <bits/stdc++.h>using namespace Std;const int N = 100000 + 5;const int BLOCK = 100;int N;int f[n][2];vector& lt;int> node;vector<int> g[n];int fa[n];void dfs (int u, int f = 1) {for (auto V:g[u]) {if (V! = f) { DFS (v, u); }} node.push_back (U); Fa[u] = f;} int solve (int k) {for (int i = 1; I <= n; i++) {f[i][0] = f[i][1] = 0; } int ret = 0; for (int u:node) {if (f[u][0] + f[u][1] + 1 >= k) {ret++; } else {if (F[fa[u]][0] < f[u][0] + 1) {f[fa[u]][1] = f[fa[u]][0]; F[fa[u]][0] = f[u][0] + 1; } else {f[fa[u]][1] = max (f[fa[u]][1], f[u][0] + 1); }}} return ret;} int main () {scanf ("%d", &n); for (int i = 1; i < n; i++) {int u, v; scanf ("%d%d", &u, &v); G[u].push_back (v); G[v].push_back (U); } dfs (1); int x = N, k = 1; while (x > BLOCK) {x = Solve (k++); printf ("%d\n", X); } for (int i = BLOCK; I >= 0; i--) {if (Solve (k)! = I|| K > N) {continue; } int l = k, R = n + 1; while (R-l > 1) {int mid = (L + r)/2; if (solve (mid) = = i) {L = mid; } else {r = Mid; }} while (K <= l) {printf ("%d\n", I); k++; }} return 0;}
1059E
In contrast to the above question, the chain requirement of the problem is vertical, considering the greed from the bottom of the chain.
For each point, pay attention to each chain coming from the child node, and the greedy choice merges the current point into the highest end of the chain.
If there is no such chain, directly according to the topic conditions to choose the highest chain.
#include <bits/stdc++.h>using namespace Std;const int N = 100000 + 5;int up[n];int dep[n], Path[n];int fa[n][21];int N, l;int W[n];long long S;long long sumw[n];vector<int> g[n];void Prepare (int u, int f = 0) {Dep[u] = dep[f] + 1; Sumw[u] = Sumw[f] + w[u]; Up[u] = u; Fa[u][0] = f; for (int i = 1; i <=; i++) {fa[u][i] = fa[fa[u][i-1]][i-1]; } int lim = L-1; for (int i = +; I >= 0; i--) {if (fa[up[u]][i]! = 0 && (1 << i) <= Lim && Sumw[u]-sumw[ Fa[fa[up[u]][i]][0]] <= S) {Up[u] = Fa[up[u]][i]; Lim-= (1 << i); }} for (int v:g[u]) {Prepare (V, u); }}int Solve (int u) {int ret = 0, best =-1; for (int v:g[u]) {ret + = solve (v); if (path[v]! = V) {if (best = =-1 | | dep[path[v] [< Dep[best]) {best = Path[v]; }}} if (best = =-1) {ret++; best = Up[u]; } Path[u] = best; return ret;} int main () {scanf ("%d%d%lld", &n, &l, &s); for (int i = 1; I <= N; i++) {scanf ("%d", &w[i]); if (W[i] > S) {printf (" -1\n"); return 0; }} for (int i = 2; I <= n; i++) {int p; scanf ("%d", &p); G[p].push_back (i); } prepare (1); printf ("%d\n", Solve (1)); return 0;}
CF 1039D Given a tree && cf1059e Split The greedy solution of the tree