题目

有一棵点数为N的树,树边有边权。给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并

将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益。

问收益最大值是多少。

输入格式

第一行两个整数N,K。

接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to)。

输入保证所有点之间是联通的。

N<=2000,0<=K<=N

输出格式

输出一个正整数,表示收益的最大值。

输入样例

5 2

1 2 3

1 5 1

2 3 1

2 4 2

输出样例

17

提示

【样例解释】

将点1,2染黑就能获得最大收益。

题解

我dp真是太弱了

很自然地可以想到设一个dp状态\(f[i][j]\),表示\(i\)为根的子树中选\(j\)个黑点的最大收益

这个时候会不会有些奇怪?这个收益具体指什么?

由题目可知,我们得到的收益必须是成对点贡献出来的,每个区域不能作为独立的个体产生贡献

我们考虑把点与点间的贡献转移到边上

对于一条边\((u,v)\),我们记\(u\)一侧的黑点数为\(b_u\),白点数为\(w_u\),\(v\)一侧类似

那么该边的贡献就为

\[w_{(u,v)} * (b_u * b_v + w_u * w_v)
\]

那么我们改变一下:\(f[i][j]\)表示\(i\)为根的子树中选\(j\)个黑点,此时子树中的边产生的最大贡献

那么就很好转移了

对于节点\(i\),其子树的贡献已经算出,我们只需要考虑其到子树的边的贡献即可

我们枚举其儿子\(t\),并枚举儿子选的黑点数,再枚举剩余的子树的黑点数计入贡献

乍一看似乎\(O(n^3)\)

仔细分析一下,我们枚举的是子树的大小,每个子树产生的复杂度为\(O(siz[t] * (siz[u] - siz[t]))\),就相当于该子树的点与剩余子树的点形成的点对的个数

也就是说,我们实质在枚举点对,而且容易发现,每对点对只会在其\(lca\)处被枚举

所以可以保证是\(O(n^2)\)的

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 2005,maxm = 10005,INF = 1000000000;
inline LL read(){
LL out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int h[maxn],ne = 2;
struct EDGE{int to,nxt; LL w;}ed[maxm];
inline void build(int u,int v,LL w){
ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v],w}; h[v] = ne++;
}
LL f[maxn][maxn],t[maxn];
int siz[maxn],fa[maxn],n,K;
inline void cmax(LL& a,LL b){if (a < b) a = b;}
void dfs(int u){
siz[u] = 1;
for (int i = 2; i <= n + 1; i++) f[u][i] = -INF;
Redge(u) if ((to = ed[k].to) != fa[u]){
fa[to] = u;
dfs(to);
for (int i = 0; i <= siz[u] + siz[to]; i++) t[i] = -INF;
for (int i = 0; i <= siz[u]; i++)
for (int j = 0; j <= siz[to]; j++)
cmax(t[i + j],f[u][i] + f[to][j] + ed[k].w * (j * (K - j) + (siz[to] - j) * (n - K - (siz[to] - j))));
siz[u] += siz[to];
for (int i = 0; i <= siz[u]; i++)
f[u][i] = t[i];
}
}
int main(){
n = read(); K = read();
int a,b; LL w;
for (int i = 1; i < n; i++){
a = read(); b = read(); w = read();
build(a,b,w);
}
dfs(1);
printf("%lld\n",f[1][K]);
return 0;
}

BZOJ4033 [HAOI2015]树上染色 【树形dp】的更多相关文章

  1. [BZOJ4033][HAOI2015]树上染色(树形DP)

    4033: [HAOI2015]树上染色 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2437  Solved: 1034[Submit][Stat ...

  2. bzoj4033 [HAOI2015]树上染色——树形DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4033 树形DP,状态中加入 x 与父亲之间的边的贡献: 边权竟然是long long... ...

  3. 洛谷 P3177 [HAOI2015]树上染色 树形DP

    洛谷 P3177 [HAOI2015]树上染色 树形DP 题目描述 有一棵点数为 \(n\) 的树,树边有边权.给你一个在 \(0 \sim n\)之内的正整数 \(k\) ,你要在这棵树中选择 \( ...

  4. 【BZOJ4033】[HAOI2015]树上染色 树形DP

    [BZOJ4033][HAOI2015]树上染色 Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染 ...

  5. bzoj 4033: [HAOI2015]树上染色 [树形DP]

    4033: [HAOI2015]树上染色 我写的可是\(O(n^2)\)的树形背包! 注意j倒着枚举,而k要正着枚举,因为k可能从0开始,会使用自己更新一次 #include <iostream ...

  6. BZOJ 4033 [HAOI2015]树上染色 ——树形DP

    可以去UOJ看出题人的题解. 这样的合并,每一个点对只在lca处被考虑到,复杂度$O(n^2)$ #include <map> #include <ctime> #includ ...

  7. BZOJ4033 HAOI2015 树上染色 【树上背包】

    BZOJ4033 HAOI2015 树上染色 Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白 ...

  8. BZOJ4033: [HAOI2015]树上染色(树形DP)

    4033: [HAOI2015]树上染色 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3461  Solved: 1473[Submit][Stat ...

  9. [bzoj4033][HAOI2015]树上染色_树形dp

    树上染色 bzoj-4033 HAOI-2015 题目大意:给定一棵n个点的树,让你在其中选出k个作为黑点,其余的是白点,收益为任意两个同色点之间距离的和.求最大收益. 注释:$1\le n\le 2 ...

  10. 【BZOJ4033】【HAOI2015】树上染色 树形DP

    题目描述 给你一棵\(n\)个点的树,你要把其中\(k\)个点染成黑色,剩下\(n-k\)个点染成白色.要求黑点两两之间的距离加上白点两两之间距离的和最大.问你最大的和是多少. \(n\leq 200 ...

随机推荐

  1. 基于 Ubuntu + nextCloud 搭建自己的私人网盘

    提醒一下,如果之前通过apache搭建了网站,不要用snap命令来搭建,否则,至少有一个无法正常运行(不要问我怎么知道的,都是血的教训啊). 你可以通过腾讯云的实验主机进行尝试. 1.基础设置 切换为 ...

  2. batchsize对收敛速度的影响

    想象一下,当mini-batch 是真个数据集的时候,是不是就退化成了 Gradient Descent,这样的话,反而收敛速度慢.你忽略了batch 增大导致的计算 batch 代价变大的问题.如果 ...

  3. 多线程编程之pthread线程深入理解

    不同的平台和操作系统上 进程和线程的实现机制不完全一致  但是一般来说线程栈都是独立的 只要得到地址就可以相互访问       Pthread是 POSIX threads 的简称,是POSIX的线程 ...

  4. Bootstrap历练实例:带表格的面板

    带表格的面板 为了在面板中创建一个无边框的表格,我们可以在面板中使用 class .table.假设有个 <div> 包含 .panel-body,我们可以向表格的顶部添加额外的边框用来分 ...

  5. webservice基础

    一.webservice概念 webservice用于异构平台之间的交互,我用Java写的程序,可以用php..net.pythod等其它语言的程序来访问我的接口.webservice有很多框架帮我们 ...

  6. cocos2dx for android 接入 fmod的过程

    cocos2dx自带的音效播放有SimpleAudioEngine和AudioEngine两个,SimpleAudioEngine可以播放简单的音效, 如果播放音效数量过多的话,多导致有些音效播放失败 ...

  7. lua 分割字符串

    -- 参数:待分割的字符串,分割字符 -- 返回:子串表.(含有空串) function split(str, split_char) local sub_str_tab = {} while tru ...

  8. LaTeX中常用数学符号总结

    博主一些小小的总结,以后会继续更的. 某个传送门. ⎝⎛•‿•⎞⎠⎝⎛•‿•⎞⎠⎝⎛•‿•⎞⎠ 1.左右一个$: 1+1=2 $1+1=2$ ($3$及以后的都需要$) 2.左右两个$: 1+1=2 ...

  9. Golang 谷歌搜索api 实现搜索引擎(前端 bootstrap + jquery)

    Golang 谷歌搜索api 实现搜索引擎(前端 bootstrap + jquery) 体验 冒号搜索 1. 获取谷歌搜索api 谷歌搜索api教程 2. 后台调用 程序入口 main.go // ...

  10. python 取余运算

    python中取余运算逻辑如下: 如果a 与d 是整数,d 非零,那么余数 r 满足这样的关系: a = qd + r , q 为整数,且0 ≤ |r| < |d|. 经过测试可发现,pytho ...