[BZOJ4033][HAOI2015]树上染色(思路+树形背包DP)
2018-01-05 21:23
573 查看
以下记sze[u]为u的子树大小,val(u,v)为边(u,v)的权值。
看到
189ad
2000的数据范围,首先猜想到可能复杂度是O(n2)。
首先想到的DP方案是:f[u][i]为u的子树内,将i个点染成黑色,在子树内的最大收益。最后答案就是f[1][m]。
然而,不难推出这个DP方案存在后效性——转移时,只有知道了子树内选出的黑色节点的深度之和,才能正确地转移。
因此换一个状态定义:f[u][i]为u的子树内,将i个点染成黑色,对答案的最大贡献。
怎么理解这个「贡献」呢?
也就是说,在这个子树内,所有同色的点对的距离之和计入贡献。而如果存在一个同色的点对v和w,v在u的子树内而w在u的子树外,则这个点对的贡献为v到u的距离。
转移,也就是做一次树形背包DP,设当前考虑到u的子节点v,之前已经遍历过的子树推出的DP结果为f′[u][]。
那么考虑合并f′[u][i]和f[v][j]得到f[u][i+j]。可以想到,在v的子树内的j个黑点可以与v的子树外的m−j个黑点配对,同样v的子树内的sze[v]−j个白点也可以与v的子树外的n−m−sze[v]+j个白点配对。并且这些点对之间的路径都经过了边(u,v)。所以转移为:
f[u][i+j]=min(f[u][i+j],f′[u][i]+f[v][j]
+(j∗(m−j)+(sze[v]−j)∗(n−m−sze[v]+j))∗val(u,v))
答案仍然是f[1][m]。
复杂度:看上去是O(n3),但是i的上界只有sze[u],因此枚举两个子树选出的黑点个数,相当于每对点都只在lca处被计算了一次,因此复杂度O(n2)。
代码:
看到
189ad
2000的数据范围,首先猜想到可能复杂度是O(n2)。
首先想到的DP方案是:f[u][i]为u的子树内,将i个点染成黑色,在子树内的最大收益。最后答案就是f[1][m]。
然而,不难推出这个DP方案存在后效性——转移时,只有知道了子树内选出的黑色节点的深度之和,才能正确地转移。
因此换一个状态定义:f[u][i]为u的子树内,将i个点染成黑色,对答案的最大贡献。
怎么理解这个「贡献」呢?
也就是说,在这个子树内,所有同色的点对的距离之和计入贡献。而如果存在一个同色的点对v和w,v在u的子树内而w在u的子树外,则这个点对的贡献为v到u的距离。
转移,也就是做一次树形背包DP,设当前考虑到u的子节点v,之前已经遍历过的子树推出的DP结果为f′[u][]。
那么考虑合并f′[u][i]和f[v][j]得到f[u][i+j]。可以想到,在v的子树内的j个黑点可以与v的子树外的m−j个黑点配对,同样v的子树内的sze[v]−j个白点也可以与v的子树外的n−m−sze[v]+j个白点配对。并且这些点对之间的路径都经过了边(u,v)。所以转移为:
f[u][i+j]=min(f[u][i+j],f′[u][i]+f[v][j]
+(j∗(m−j)+(sze[v]−j)∗(n−m−sze[v]+j))∗val(u,v))
答案仍然是f[1][m]。
复杂度:看上去是O(n3),但是i的上界只有sze[u],因此枚举两个子树选出的黑点个数,相当于每对点都只在lca处被计算了一次,因此复杂度O(n2)。
代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> 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; } typedef long long ll; const int N = 2005, M = 4005; int n, m, ecnt, nxt[M], adj , go[M], val[M], sze ; ll f , x ; 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, j; sze[u] = 1; for (int e = adj[u], v; e; e = nxt[e]) { if ((v = go[e]) == fu) continue; dfs(v, u); for (i = 0; i <= sze[u] + sze[v]; i++) x[i] = 0; for (i = 0; i <= sze[u]; i++) for (j = 0; j <= sze[v]; j++) { if (i + j > m || n - m < sze[v] - j) continue; ll delta = (1ll * j * (m - j) + 1ll * (sze[v] - j) * ((n - m) - (sze[v] - j))) * val[e]; x[i + j] = max(x[i + j], f[u][i] + f[v][j] + delta); } for (i = 0; i <= sze[u] + sze[v]; i++) f[u][i] = x[i]; sze[u] += sze[v]; } } int main() { int i, x, y, z; n = read(); m = read(); for (i = 1; i < n; i++) x = read(), y = read(), z = read(), add_edge(x, y, z); dfs(1, 0); cout << f[1][m] << endl; return 0; }
相关文章推荐
- BZOJ 4033: [HAOI2015]树上染色 树形dp
- BZOJ4033 [HAOI2015]树上染色 【树形dp】
- 【BZOJ4033】【HAOI2015】树上染色 树形DP
- BZOJ_4033_[HAOI2015]树上染色_树形DP
- [树形DP] BZOJ 4033 [HAOI2015]树上染色
- [bzoj4033][HAOI2015]树上染色(树形dp)
- [BZOJ4033][HAOI2015]树上染色(树形DP)
- [树形DP]BZOJ 4033—— [HAOI2015]树上染色
- [bzoj4033][HAOI2015]树上染色_树形dp
- 【BZOJ4033】[HAOI2015]树上染色 树形DP
- BZOJ 4033 [HAOI2015]树上染色 ——树形DP
- [BZOJ]4033: [HAOI2015]树上染色 树形DP
- bzoj 4033: [HAOI2015]树上染色【树形dp】
- bzoj 4033: [HAOI2015]树上染色(树形DP)
- bzoj 4033: [HAOI2015]树上染色 树形dp
- BZOJ4033:[HAOI2015]树上染色(树形dp)
- bzoj 4033: [HAOI2015]树上染色 [树形DP]
- 【BZOJ】4033: [HAOI2015]树上染色 树上背包
- [bzoj4033][HAOI2015]树上染色【dp】
- BZOJ4033[HAOI2015] 树上染色 解题报告【树上DP】