题解
题解
所构造树的任一边的权值上界都为 M M M。设节点 u u u 的度为 d u d_u du,则与 u u u 相连的边中, u u u 对 ⌊ d u / 2 ⌋ + 1 \lfloor d_u/2\rfloor+1 ⌊du/2⌋+1 条边有边权上界为 A u A_u Au 的约束,对其余 d u − ( ⌊ d u / 2 ⌋ + 1 ) d_u-(\lfloor d_u/2\rfloor+1) du−(⌊du/2⌋+1) 条边无边权上界的约束。
考虑任意节点 u u u,若其非根节点,则仅存在一条与祖先节点的连边,这条边存在两种可能,即 u u u 是否对其有上界约束 A u A_u Au。 d p [ i ] [ j ] dp[i][j] dp[i][j] 代表在状态 j j j 下,以 i i i 为根的子树比边权和的最大值; j = 0 j=0 j=0 则代表节点 i i i 对边 ( p a r e n t i , i ) (parent_i,i) (parenti,i) 无边权上界的限制, j = 1 j=1 j=1 则反之。
问题转化为,已知 d p [ c h i l d i ] [ k ] ( k ∈ [ 0 , 1 ] ) dp[child_i][k](k\in [0,1]) dp[childi][k](k∈[0,1]),任取 d i − ( ⌊ d i / 2 ⌋ + 1 ) − j d_i-(\lfloor d_i/2\rfloor+1)-j di−(⌊di/2⌋+1)−j 条边 ( i , c h i l d i ) (i,child_i) (i,childi),使 i i i 对其无上界约束,而对其余 ( i , c h i l d i ) (i,child_i) (i,childi) 有上界约束 A i A_i Ai,使 d p [ i ] [ j ] dp[i][j] dp[i][j] 最大。对 i i i 与任一子节点连边 ( i , c h i l d i ) (i,child_i) (i,childi) 的边权,只有 i i i、 c h i l d i child_i childi 分别是否对其有上界限制四种可能;显然, i i i 对边存在上界约束的情况下,子节点对 i i i 的贡献要不大于无约束的情况。那么答案预取为所有无约束情况的和;将无约束情况与有约束情况做差,并排序,贪心地从大到小取 d i − ( ⌊ d i / 2 ⌋ + 1 ) − j d_i-(\lfloor d_i/2\rfloor+1)-j di−(⌊di/2⌋+1)−j 条边的差值即可。
总时间复杂度 O ( N log N ) O(N\log N) O(NlogN)。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
typedef long long ll;
const int maxn = 500005, inf = 0x3f3f3f3f;
int N, M, A[maxn];
ll B[maxn][2], C[maxn], dp[maxn][2];
vector<int> G[maxn];
void dfs(int u, int p)
{
int son = 0;
ll res = 0;
for (auto &v : G[u])
if (v != p)
dfs(v, u);
for (auto &v : G[u])
if (v != p)
{
B[son][0] = max(A[v] + dp[v][1], M + dp[v][0]);
B[son][1] = max(min(A[u], A[v]) + dp[v][1], A[u] + dp[v][0]);
C[son] = B[son][0] - B[son][1];
res += B[son][1];
++son;
}
sort(C, C + son);
int num = ((son + (p == -1 ? 0 : 1)) >> 1) + 1;
rep(i, num - 1, son) res += C[i];
dp[u][1] = res;
dp[u][0] = num <= son ? res - C[num - 1] : -inf;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> N >> M;
rep(i, 0, N) cin >> A[i];
rep(i, 1, N)
{
int u, v;
cin >> u >> v;
--u, --v;
G[u].push_back(v), G[v].push_back(u);
}
dfs(0, -1);
cout << dp[0][0] << '\n';
return 0;
}