P6748『MdOI R3』树形 DP + 贪心

题解

传送门 P6748『MdOI R3』Fallen Lord

题解

所构造树的任一边的权值上界都为 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;
}

おすすめ

転載: blog.csdn.net/neweryyy/article/details/120099626