「6月雅礼集训 2017 Day11」tree
Posted 逢山开路 遇水架桥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「6月雅礼集训 2017 Day11」tree相关的知识,希望对你有一定的参考价值。
【题目大意】
给出一棵带权树,有两类点,一类黑点,一类白点。
求切断黑点和白点间路径的最小代价。
$n \leq 10^5$
【题解】
直接最小割能过。。但是树形dp明显更好写
设$f_{x,0/1/2}$表示$x$这个点的子树中,0表示没有带颜色的点连到这个子树的根$x$,1表示黑点连到$x$,2表示白点连到$x$。
直接转移即可。具体看代码,挺好推得。。
# include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef long double ld; const int N = 1e5 + 10, M = 2e5 + 10; const ll inf = 1e17; int n, d[N]; int head[N], nxt[M], to[M], w[M], tot = 0; inline void add(int u, int v, int _w) { ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; w[tot] = _w; } inline void adde(int u, int v, int _w) { add(u, v, _w), add(v, u, _w); } ll f[N][3]; // 没有有颜色点连到根上,只有黑点连到根上,只有白点连到根上 inline void dp(int x, int fa = 0) { f[x][0] = inf, f[x][1] = f[x][2] = 0; if(d[x] == 0) f[x][0] = 0; if(d[x] == 2) f[x][1] = inf; if(d[x] == 1) f[x][2] = inf; for (int i=head[x]; i; i=nxt[i]) { if(to[i] == fa) continue; int y = to[i]; dp(y, x); f[x][0] += min(f[y][0], min(f[y][1], f[y][2]) + w[i]); if(f[x][0] > inf) f[x][0] = inf; f[x][1] += min(min(f[y][0], f[y][1]), f[y][2] + w[i]); if(f[x][1] > inf) f[x][1] = inf; f[x][2] += min(min(f[y][0], f[y][2]), f[y][1] + w[i]); if(f[x][2] > inf) f[x][2] = inf; } // printf("x = %d, f[x][0] = %I64d, f[x][1] = %I64d, f[x][2] = %I64d\n", x, f[x][0], f[x][1], f[x][2]); } int main() { freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); cin >> n; for (int i=1, u, v, _w; i<n; ++i) { scanf("%d%d%d", &u, &v, &_w); adde(u, v, _w); } int T; cin >> T; for (int i=1, x; i<=T; ++i) { scanf("%d", &x); d[x] = 1; } cin >> T; for (int i=1, x; i<=T; ++i) { scanf("%d", &x); d[x] = 2; } dp(1); cout << min(f[1][0], min(f[1][1], f[1][2])); return 0; } /* 6 1 2 5 2 4 4 2 5 1 1 3 2 3 6 7 1 4 2 5 6 */
以上是关于「6月雅礼集训 2017 Day11」tree的主要内容,如果未能解决你的问题,请参考以下文章