HDU 5834 [树形dp]
/*
题意:n个点组成的树,点和边都有权值,当第一次访问某个点的时候获得利益为点的权值
每次经过一条边,丢失利益为边的权值。问从第i个点出发,获得的利益最大是多少。
输入:
测试样例组数T
n
n个数每个点的权值
n-1条无向边 a b c a和b是点的标号,c是边的权值。
思路:
注意题目只强调是从某个点出发,并不一定要回到该点。
考虑树形DP。
先随便定义一个树根。然后对于某个点,我们需要维护它子树方向的两个值
1.从该点出发,最终要回到该点的利益的最大值
2.从该点出发,最终不必回到该点的利益的最大值,以及最后一次从该点出发的是哪个儿子节点。
3.从该点出发,最终不必回到该点的利益的第二大值,以及最后一次从该点出发的是哪个儿子节点。
先求出回到该点的利益的最大值,然后枚举它的儿子节点,作为最后出去的节点,即该节点不返回。
第二和第三个值把枚举所有儿子作为最后一次出发的情况然后排序记录下前两个就可以了。
以上是第一次DFS所做的工作。
然后对于每个点维护三个值,进行第二次DFS。
1.从该点出发所有方向(子树方向和父亲方向)回到该点的利益的最大值。
2.从该点出发所有方向,不必回到该点的利益的最大值,并保存最后一个出发的儿子节点的标号。
3.从该点出发所有方向,不必回到该点的利益的第二大值,并保存最后一个出发的儿子节点的标号。
第1个值的维护只需要将子树方向和减掉本身所在子树所影响的父亲方向的值加起来即可。
对于第二个和第三个值,我们可以将子树方向上最大的两个值加上父亲方向回来所带来的利益,与
父亲方向作为最后一次出发的点不回来的利益这三个值中求取两个最大的即可。
之所以要维护第二大的值,是因为当父亲节点最终的答案(即可以不回来)的最后一次访问的点恰
好是我们要求取的它的儿子节点的时候,我们可以用次大的值来确定当该儿子节点的父亲方向作为
最后一次访问的方向的时候的利益。
最后所有的ans[i][1]就是答案。
总结“
1.树形DP维护的时候经常需要维护次大值甚至第三大值,这是由于父亲方向的最优问题是否关系到
儿子节点所决定的。
*/ #include<bits/stdc++.h>
#define N 100050
using namespace std;
struct edge{
int id;
edge *next;
long long w;
};
struct st{
st(int a,long long b){
id=a;
ans=b;
}
long long ans;
int id;
};
bool cmp(st a,st b){
return a.ans>b.ans;
}
int ednum;
edge edges[N*];
edge *adj[N];
long long v[N],son[N][],ans[N][];
int fa[N],id[N][];
inline void addedge(int a,int b,long long w){
edge *tmp=&edges[ednum++];
tmp->w=w;
tmp->id=b;
tmp->next=adj[a];
adj[a]=tmp;
}
void dfs(int pos){
son[pos][]+=v[pos];
for(edge *it=adj[pos];it;it=it->next){
if(fa[pos]!=it->id){
fa[it->id]=pos;
dfs(it->id);
if(son[it->id][]-*it->w>){
son[pos][]+=son[it->id][]-*it->w;
}
}
}
son[pos][]=son[pos][];
vector<st>mv;
mv.push_back(st(,son[pos][]));
mv.push_back(st(,son[pos][]));
for(edge *it=adj[pos];it;it=it->next){
if(fa[it->id]==pos){
if(son[it->id][]-it->w>){
long long tn=son[pos][]+son[it->id][]-it->w;
if(son[it->id][]-*it->w>)tn-=son[it->id][]-*it->w;
if(tn>son[pos][]){
mv.push_back(st(it->id,tn));
}
}
}
}
sort(mv.begin(),mv.end(),cmp);
son[pos][]=mv[].ans;
id[pos][]=mv[].id;
son[pos][]=mv[].ans;
id[pos][]=mv[].id;
}
void dfs2(int pos){
if(pos==){
for(int i=;i<;i++){
ans[pos][i]=son[pos][i];
}
}
for(edge *it=adj[pos];it;it=it->next){
if(fa[it->id]==pos){
long long tans=ans[pos][]-*it->w;
if(son[it->id][]-*it->w>){
tans-=son[it->id][];
tans+=*it->w;
}
tans=max(0LL,tans);
ans[it->id][]=son[it->id][]+tans;
vector<st>mv;
mv.push_back(st(,ans[it->id][]));
mv.push_back(st(,ans[it->id][]));
for(int i=;i<;i++){
mv.push_back(st(id[it->id][i],son[it->id][i]+tans));
}
if(id[pos][]!=it->id){
long long tm=ans[pos][];
tm+=son[it->id][];
if(son[it->id][]-*it->w>){
tm-=son[it->id][]-*it->w;
}
mv.push_back(st(id[pos][],tm-it->w));
}
else{
long long tm=ans[pos][];
tm+=son[it->id][];
if(son[it->id][]-*it->w>){
tm-=son[it->id][]-*it->w;
}
mv.push_back(st(id[pos][],tm-it->w));
}
sort(mv.begin(),mv.end(),cmp);
ans[it->id][]=mv[].ans;
id[it->id][]=mv[].id;
ans[it->id][]=mv[].ans;
id[it->id][]=mv[].id;
dfs2(it->id);
}
}
}
int main()
{
int t;
scanf("%d",&t);
int cas=;
while(t--){
cas++;
printf("Case #%d:\n",cas);
int n;
scanf("%d",&n);
for(int i=;i<=n;i++){
for(int j=;j<;j++){
son[i][j]=id[i][j]=ans[i][j]=;
}
adj[i]=NULL;
fa[i]=;
}
ednum=;
for(int i=;i<=n;i++)scanf("%lld",v+i);
for(int i=;i<n;i++){
int a,b;long long w;
scanf("%d%d%lld",&a,&b,&w);
addedge(a,b,w);
addedge(b,a,w);
}
dfs();
dfs2();
for(int i=;i<=n;i++){
printf("%lld\n",ans[i][]);
}
}
}
HDU 5834 [树形dp]的更多相关文章
- hdu 4123 树形DP+RMQ
http://acm.hdu.edu.cn/showproblem.php? pid=4123 Problem Description Bob wants to hold a race to enco ...
- HDU 1520 树形dp裸题
1.HDU 1520 Anniversary party 2.总结:第一道树形dp,有点纠结 题意:公司聚会,员工与直接上司不能同时来,求最大权值和 #include<iostream> ...
- HDU 1561 树形DP入门
The more, The Better Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- HDU 2196树形DP(2个方向)
HDU 2196 [题目链接]HDU 2196 [题目类型]树形DP(2个方向) &题意: 题意是求树中每个点到所有叶子节点的距离的最大值是多少. &题解: 2次dfs,先把子树的最大 ...
- HDU 1520 树形DP入门
HDU 1520 [题目链接]HDU 1520 [题目类型]树形DP &题意: 某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上司,现在已知 ...
- codevs 1380/HDU 1520 树形dp
1380 没有上司的舞会 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 回到问题 题目描述 Description Ural大学有N个职员 ...
- hdu 4267 树形DP
思路:先dfs一下,找出1,n间的路径长度和价值,回溯时将该路径长度和价值清零.那么对剩下的图就可以直接树形dp求解了. #include<iostream> #include<al ...
- hdu 4607 (树形DP)
当时比赛的时候我们找出来只要求出树的最长的边的节点数ans,如果要访问点的个数n小于ans距离直接就是n-1 如果大于的话就是(n-ans)*2+ans-1,当时求树的直径难倒我们了,都不会树形dp ...
- hdu 1520 (树形DP)
dp[i][0]表示i不参加 dp[i][1]表示i参加 简单的树形dp #include<stdio.h> #include<string.h> #define N 6100 ...
随机推荐
- Windows电脑上安装Appium
Windows机器上,除了JAVA的安装和配置外,安装Appium需要如下设置: 0. 安装SDK后设置环境变量 1)新建JAVA_HOME: SDK安装路径,如D:\Program Files\Ja ...
- form表单元素类型
<form> <input type="text"> <input type="password"> <input t ...
- Spring Data Solr教程(翻译) 开源的搜索服务器
Solr是一个使用开源的搜索服务器,它采用Lucene Core的索引和搜索功能构建,它可以用于几乎所有的编程语言实现可扩展的搜索引擎. Solr的虽然有很多优点,建立开发环境是不是其中之一.此博客条 ...
- NFC会员管理-转载自http://technews.cn/2014/09/13/nfc-sticker/
基隆的百年名店“李鹄饼店”误用馊水油,客人纷纷上门退货,因退货条件宽松,客人一货两退,造成巨大的损失.为了平息客人的愤怒,店家允许客人凭发 票或商品办理退货,有的客人先用发票退一次钱,再用商品退一次钱 ...
- Android学习笔记1 android adb启动失败问题 adb server is out of date. killing...
下面是Android的学习笔记,原文地址. 我是使用adb devices出现如下红字错误, 使用第一种方法方法,结果关掉豌豆荚就可以了. android adb启动失败问题 adb server i ...
- Linux中ftp不能上传文件/目录的解决办法
在linux中不能上传文件或文件夹最多的问题就是权限问题,但有时也不一定是权限问题了,像我就是空间不够用了,下面我来总结一些ftp不能上传文件/目录的解决办法 在排除用户组和权限等问题后,最可能引 ...
- [原]Fedora Linux环境下的应用工具总结
一.办公类软件 1.Office办公:WPS 二.网络通信类软件 1.浏览器:Chrome 2.远程桌面:rdesktop(适用于Windows系列) 三.操作系统设置与优化 1.3D桌面管理:Com ...
- jQuery实现登录提示
实现效果:将鼠标聚焦到邮箱地址文本框时,文本框 内的"请输入邮箱地址"文字将被清除: 若没有输入任何内容,鼠标移除后邮箱地址文本框被还原. <!DOCTYPE html& ...
- webApi文档好帮手-apidoc使用教程
来源:http://blog.csdn.net/xumin198908/article/details/41964159 在开发后台接口的过程中,我们肯定要提供一份api接口文档给终端app. 目前大 ...
- [转][色彩 A] – 永远不要使用纯黑
原文地址:http://www.cgjoy.com/forum.php?mod=viewthread&tid=110762&extra=page%3D1%26filter%3Dtype ...