Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
If you detach a node , you detach the whole subtree of . Every node in that detached subtree has its depth changed by the same amount.
For a fixed move , the gain is
where is the sum of values in 's subtree.
The original cost for every subtree is easy bottom-up:
Look at the LCA of the moved node and the target node . If that LCA is not the current root , then the whole operation lives inside exactly one child subtree of .
Key greedy: if the LCA is and is somewhere inside child subtree , moving the direct child is always at least as good as moving deeper . It has a larger subtree sum and loses less depth. So crossing moves at only need ordered pairs of distinct children.
Root the tree at . For each node , let
and let be the maximum absolute depth of any node in .
First compute the cost before any operation. If is the cost of when rooted at , then every node inside a child subtree becomes one edge farther when viewed from . Therefore
Now we only need the best possible gain from one operation.
Suppose we detach node and attach it under node . The whole subtree of moves together, and every node in it changes depth by
So the gain is
The dangerous-looking part is that could be any descendant. Trying all pairs is obviously dead on arrival.
Here is the useful split. For a fixed subtree root , take an optimal operation and let
Because must be outside , is a strict ancestor of .
If , then both and lie inside the same child subtree of . That operation is already counted in that child. So those cases are handled by taking the maximum answer among children.
The only new operations created at node are the ones with . Then lies inside one child subtree , and lies either at or inside a different child subtree .
If , the gain is never positive. Moving something upward or keeping a direct child where it already was does not help, and we are allowed to do nothing.
So must be in a different child subtree. For fixed child containing and fixed target branch , the deepest possible in is best. Now comes the main greedy point: the best inside branch is just the direct child itself.
Why? For any descendant of ,
and
The first factor is larger, and the depth gain is also larger. Since moving under is legal, moving deeper inside can never beat it. That false assumption is the whole trap; once you kill it, the problem chills out.
Therefore the best crossing move at is
where are children of . The term comes from
For each child , we only need the largest among the other children. Store the top two child subtree depths, so this is per child.
Let be the maximum gain possible inside . The recurrence is
Finally,
Edge cases are clean:
All values need long long: sums and costs can reach about .
The algorithm is one root traversal plus one reverse traversal, so the complexity is
per test case, with memory.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ll> a(n + 1), sum(n + 1), base(n + 1), best(n + 1), mx(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
vector<vector<int>> g(n + 1);
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> parent(n + 1), depth(n + 1), order;
order.reserve(n);
order.push_back(1);
for (int i = 0; i < (int)order.size(); i++) {
int u = order[i];
for (int v : g[u]) {
if (v == parent[u]) continue;
parent[v] = u;
depth[v] = depth[u] + 1;
order.push_back(v);
}
}
for (int i = n - 1; i >= 0; i--) {
int u = order[i];
sum[u] = a[u];
mx[u] = depth[u];
ll top1 = -1, top2 = -1;
int topChild = -1;
for (int v : g[u]) {
if (parent[v] != u) continue;
sum[u] += sum[v];
base[u] += base[v] + sum[v];
best[u] = max(best[u], best[v]);
mx[u] = max(mx[u], mx[v]);
if (mx[v] > top1) {
top2 = top1;
top1 = mx[v];
topChild = v;
} else if (mx[v] > top2) {
top2 = mx[v];
}
}
for (int v : g[u]) {
if (parent[v] != u) continue;
ll otherDepth = (v == topChild ? top2 : top1);
if (otherDepth != -1) {
best[u] = max(best[u], sum[v] * (otherDepth - depth[u]));
}
}
}
for (int i = 1; i <= n; i++) {
cout << base[i] + best[i] << (i == n ? '\n' : ' ');
}
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ll> a(n + 1), sum(n + 1), base(n + 1), best(n + 1), mx(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
vector<vector<int>> g(n + 1);
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> parent(n + 1), depth(n + 1), order;
order.reserve(n);
order.push_back(1);
for (int i = 0; i < (int)order.size(); i++) {
int u = order[i];
for (int v : g[u]) {
if (v == parent[u]) continue;
parent[v] = u;
depth[v] = depth[u] + 1;
order.push_back(v);
}
}
for (int i = n - 1; i >= 0; i--) {
int u = order[i];
sum[u] = a[u];
mx[u] = depth[u];
ll top1 = -1, top2 = -1;
int topChild = -1;
for (int v : g[u]) {
if (parent[v] != u) continue;
sum[u] += sum[v];
base[u] += base[v] + sum[v];
best[u] = max(best[u], best[v]);
mx[u] = max(mx[u], mx[v]);
if (mx[v] > top1) {
top2 = top1;
top1 = mx[v];
topChild = v;
} else if (mx[v] > top2) {
top2 = mx[v];
}
}
for (int v : g[u]) {
if (parent[v] != u) continue;
ll otherDepth = (v == topChild ? top2 : top1);
if (otherDepth != -1) {
best[u] = max(best[u], sum[v] * (otherDepth - depth[u]));
}
}
}
for (int i = 1; i <= n; i++) {
cout << base[i] + best[i] << (i == n ? '\n' : ' ');
}
}
return 0;
}