[BZOJ3677/UOJ#105][APIO2014]Beads and wires 连珠线(树形dp+换根)

Address

https://www.lydsy.com/JudgeOnline/problem.php?id=3677
http://uoj.ac/problem/105

Solution

考虑一个子树内的两种情况:
这里写图片描述
这里写图片描述
容易得出一个树形 dp 状态:
f [ u ] 表示以 u 为根的子树,连接 u 和其父节点的边为红色, u 的子树内的最大收益。如果不存在方案则为 (图 1 )。
g [ u ] 表示以 u 为根的子树,连接 u 和其父节点的边为蓝色, u 的子树内的最大收益。如果不存在方案则为 (图 2 )。
特殊地,如果 u 是整棵树的根(我们不失一般性地选 1 为根),则 f [ u ] 表示整棵树的最大收益。
如果 u 是叶子,那么

f [ u ] = 0 , g [ u ] =

f 的转移即考虑所有子树:
f [ u ] = v s o n [ u ] max ( f [ v ] , g [ v ] + l e n ( u , v ) )

其中 l e n ( u , v ) 为边 ( u , v ) 的长度。
g 的转移则是枚举 u 的子节点 v 使 ( u , v ) 为蓝边:
g [ u ] = max v s o n [ u ] { l e n ( u , v ) + f [ v ] + w s o n [ u ] , w v max ( f [ v ] , g [ v ] + l e n ( u , v ) ) }

需要使用前缀 & 后缀最大值优化。
看上去最后答案就是 f [ 1 ] ,但是很遗憾,不是。为什么呢?
我们忽略了一种情况:
这里写图片描述
但继续分析可以发现,下图这种情况是不会发生的:
这里写图片描述
这样就能得出:存在一个点 r ,最优解在以 r 为根的子树上不会出现我们之前忽略的这种情况。
所以,以每个点为根进行 dp 就能达到目的。但这是 O ( n 2 ) 的。考虑到枚举根特别浪费时间,可以在树形 dp 上使用换根技巧, O ( n ) 求出以所有点为根的答案。
这样,答案就是以所有点为根的 f 的最大值。

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
#define Tree(u) for (int e = adj[u], v; e; e = nxt[e]) if ((v = go[e]) != fu)
using namespace std;
inline int read() {
    int res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    return bo ? ~res + 1 : res;
}
const int N = 2e5 + 5, M = N << 1, INF = 0x3f3f3f3f;
int n, ecnt, nxt[M], adj[N], go[M], val[M], f[N], g[N], h[N], s[N], ps[N],
suml[N], sumr[N], maxl[N], maxr[N], len[N], va[N], _l[N];
void add_edge(int u, int v, int w) {
    nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w;
    nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u; val[ecnt] = w;
}
void dfs(int u, int fu) {
    int i, cnt = 0; Tree(u) cnt++, dfs(v, u);
    if (!cnt) return (void) (f[u] = 0, g[u] = -INF);
    int sp = 0; f[u] = g[u] = 0; Tree(u) {
        int orz = max(f[v], val[e] + g[v]);
        if (orz < 0) sp++; else f[u] += orz;
    }
    if (sp) f[u] = -INF; cnt = 0; Tree(u) suml[++cnt] = sumr[cnt]
        = max(f[v], val[e] + g[v]), ps[cnt] = v, len[cnt] = val[e];
    For (i, 1, cnt) suml[i] += suml[i - 1]; sumr[cnt + 1] = 0;
    Rof (i, cnt, 1) sumr[i] += sumr[i + 1]; g[u] = -INF; if (!sp) For (i, 1, cnt) {
        int v; if (f[v = ps[i]] >= 0)
            g[u] = max(g[u], len[i] + f[v] + suml[i - 1] + sumr[i + 1]);
    }
}
void dfs2(int u, int fu) {
    int i, sp = 0, rp = 0, cnt = 0; if (fu) {
        va[++cnt] = max(h[u], _l[u] + s[u]); len[cnt] = _l[u];
        ps[cnt] = -1; if (va[cnt] < 0) rp++;
    }
    Tree(u) {
        va[++cnt] = max(f[v], val[e] + g[v]); len[cnt] = val[e];
        ps[cnt] = v; if (va[cnt] < 0) sp++;
    }
    suml[0] = sumr[cnt + 1] = 0; maxl[0] = maxr[cnt + 1] = -INF;
    For (i, 1, cnt) suml[i] = suml[i - 1] + va[i],
        maxl[i] = max(maxl[i - 1], ps[i] == -1 ? h[u] + len[i] - va[i] :
        f[ps[i]] + len[i] - va[i]);
    Rof (i, cnt, 1) sumr[i] = sumr[i + 1] + va[i],
        maxr[i] = max(maxr[i + 1], ps[i] == -1 ? h[u] + len[i] - va[i] :
        f[ps[i]] + len[i] - va[i]);
    Tree(u) h[v] = s[v] = -INF; if (rp || sp > 1) {
        Tree(u) _l[v] = val[e], dfs2(v, u); return;
    }
    if (sp) {
        int v = 1; while (va[v] >= 0) v++;
        h[ps[v]] = sumr[1] - va[v]; s[ps[v]] = sumr[1] - va[v]
            + max(maxl[v - 1], maxr[v + 1]);
    }
    else {
        For (i, (fu ? 2 : 1), cnt) {
            int v = ps[i]; h[v] = sumr[1] - va[i];
            s[v] = sumr[1] - va[i] + max(maxl[i - 1], maxr[i + 1]);
        }
    }
    Tree(u) _l[v] = val[e], dfs2(v, u);
}
int main() {
    int i, x, y, z; n = read(); For (i, 1, n - 1)
        x = read(), y = read(), z = read(), add_edge(x, y, z);
    int ans = 0; dfs(1, 0); dfs2(1, 0); For (i, 1, n)
        ans = max(ans, max(f[i] + h[i], f[i] + s[i] + _l[i]));
    cout << ans << endl; return 0;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/81047266