HDU5886 Tower Defence 【两遍树形dp】【最长链预处理】
题意:N个点的一棵带权树。切掉某条边的价值为切后两树直径中的最大值。求各个边切掉后的价值和(共N-1项)。
解法一:
强行两遍dp,思路繁琐,维护东西较多:
dis表示以i为根的子树的直径,dis2表示切掉以i为根的子树后的直径。
第一遍dp,记录
down[][0]:从i结点向下的最大距离
down[][1]:与down[][0]无交集的向下次大距离
dis:以i为根的子树的直径
第二遍dp,记录
up:从i结点向上的最远距离, 可以是w+父节点的up,也可以是w+父节点的down(判断一下down是否与w有重合)
dis2:切掉以i为根的子树后的直径
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define pii pair<int, int>
#define mp make_pair
typedef long long ll;
const int N = 1e5+;
void gmax(int& a, int b){ if(a < b) a = b;}
int n;
ll ans;
int down[N][], up[N], dis[N], dis2[N]; int head[N], nex[N*], tot;
pii edge[N*];
void init(){
tot = ;
memset(head, -, sizeof(head));
memset(down, , sizeof(down));
memset(up, , sizeof(up));
memset(dis, , sizeof(dis));
memset(dis2, , sizeof(dis2));
}
void add(int u, int v, int w){
edge[tot] = mp(v, w);
nex[tot] = head[u];
head[u] = tot++;
}
//down[][0]:从i结点向下的最大距离
//down[][1]:与down[][0]无交集的向下次大距离
//dis:以i为根的子树的直径
void dfs(int fa, int x){
// printf("dfs x %d, fa %d\n", x, fa);
//down[x][0] = down[x][1] = dis[x] = dis2[x] = up[x] = 0;
for(int i = head[x]; ~i; i = nex[i]){
int y = edge[i].X, w = edge[i].Y;
if(y == fa) continue ;
dfs(x, y);
if(down[y][]+w > down[x][])
down[x][] = down[x][], down[x][] = down[y][]+w;
else if(down[y][]+w > down[x][])
down[x][] = down[y][]+w;
gmax(dis[x], dis[y]);
}
gmax(dis[x], down[x][]+down[x][]);
}
//up:从i结点向上的最远距离
//dis2:切掉以i为根的子树后的直径
multiset<int>::iterator it;
void dfs2(int fa, int x){
if(fa != -) ans += max(dis[x], dis2[x]);
// printf("fa %d, x %d\n", fa, x);
multiset<int> se, se2;//兄弟树的直径, x往各个兄弟树的最长路
for(int i = head[x]; ~i; i = nex[i]){
int y = edge[i].X, w = edge[i].Y;
if(y == fa) continue ;
se.insert( dis[y] );
se2.insert( down[y][]+w );
}
for(int i = head[x]; ~i; i = nex[i]){
int y = edge[i].X, w = edge[i].Y;
if(y == fa) continue ;
up[y] = up[x]+w;
if(down[y][]+w == down[x][])
gmax(up[y], down[x][]+w);
else gmax(up[y], down[x][]+w);
it = se.find( dis[y] ), se.erase(it);
it = se2.find( down[y][]+w ), se2.erase(it);
dis2[y] = dis2[x];
if(!se.empty())
gmax(dis2[y], *se.rbegin());
if(se2.empty()) gmax(dis2[y], up[x]);
else gmax(dis2[y], up[x]+*se2.rbegin());
if(se2.size() >= ){
int tmp = ;
it = se2.end();
tmp += *--it;
tmp += *--it;
gmax(dis2[y], tmp);
}
dfs2(x, y);
se.insert( dis[y] );
se2.insert( down[y][]+w );
}
}
void debug(int n){
for(int i = ; i <= n; i++)
printf("%d: down0 %d, down1 %d, dis %d, dis2 %d, up %d\n", i, down[i][], down[i][], dis[i], dis2[i], up[i]);
}
int main(){
int t, u, v, w; scanf("%d", &t);
while(t--) {
init();
scanf("%d", &n);
for(int i = ; i < n; i++){
scanf("%d%d%d", &u, &v, &w);
add(u, v, w), add(v, u, w);
}
ans = ;
dfs(-, );
dfs2(-, );
printf("%lld\n", ans);
}
return ;
}
解法二:
先求出原树的直径。
从直径两端分别来一次dp
切的边不在直径上,价值为直径;
切的边在直径上,由直径两端的dp得解。
HDU5886 Tower Defence 【两遍树形dp】【最长链预处理】的更多相关文章
- 【树形dp 最长链】bzoj1912: [Apio2010]patrol 巡逻
富有思维性的树形dp Description Input 第一行包含两个整数 n, K(1 ≤ K ≤ 2).接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, ...
- P3565 由简单的树形dp 引入 长链刨分
这道题感觉不太行 因为自己没想出来. 先说一下暴力吧,取三个点 让两两之间的距离相等怎么做呢,看起来是很复杂的样子的,但是仔细观察发现 答案出自一个点的儿子之间 或者儿子和父亲之间. 暴力枚举三个点然 ...
- LOJ3053 十二省联考2019 希望 容斥、树形DP、长链剖分
传送门 官方题解其实讲的挺清楚了,就是锅有点多-- 一些有启发性的部分分 L=N 一个经典(反正我是不会)的容斥:最后的答案=对于每个点能够以它作为集合点的方案数-对于每条边能够以其两个端点作为集合点 ...
- 洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)
洛谷题目传送门 ZJOI的考场上最弱外省选手T2 10分成功滚粗...... 首先要想到30分的结论 说实话Day1前几天刚刚刚掉了SDOI2017的树点涂色,考场上也想到了这一点 想到了又有什么用? ...
- 洛谷 P1352 没有上司的舞会【树形DP/邻接链表+链式前向星】
题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...
- HDU 4612 Warm up (边双连通分量+DP最长链)
[题意]给定一个无向图,问在允许加一条边的情况下,最少的桥的个数 [思路]对图做一遍Tarjan找出桥,把双连通分量缩成一个点,这样原图就成了一棵树,树的每条边都是桥.然后在树中求最长链,这样在两端点 ...
- HDU 4607 Park Visit (DP最长链)
[题目]题意:N个城市形成一棵树,相邻城市之间的距离是1,问访问K个城市的最短路程是多少,共有M次询问(1 <= N, M <= 100000, 1 <= K <= N). [ ...
- Codeforces Round #135 (Div. 2) D - Choosing Capital for Treeland(两种树形DP)
- BZOJ.2159.Crash的文明世界(斯特林数 树形DP)
BZOJ 洛谷 挺套路但并不难的一道题 \(Description\) 给定一棵\(n\)个点的树和\(K\),边权为\(1\).对于每个点\(x\),求\(S(x)=\sum_{i=1}^ndis( ...
随机推荐
- css缩写
颜色: 16进制的色彩值为六位数,如果每两位的值相同,可以缩写一半. 如:#000000=#000: #223344=#234: 盒子的尺寸: 如margin:value; 一个值表示所有边,两个值表 ...
- java程序 输入10个数字并求和
课程作业: 模仿JavaAppArguments.java示例,编写编写一个程序,此程序从命令行接受多个数字,求和之后输出结果. 设计思想: 先从命令行读出数字,然后计算各个数字之和.求出结果. 流程 ...
- Cocos2dx lua 3D实例代码
用cocoside 创建一个项目 cocos2dx lua 项目即可 ,然后替换掉gamescene 就可以,具体效果还有函数的参数,相信大家一看就明白.简单说下ide 创建的 cocos lua 项 ...
- linux修改mac地址
先禁用网卡ifconfig eth0 down 再用ifconfig eth0 hw ether 新地址 这样就可以了 要想永久修改的话,在/etc/rc.d/rc.local里加上下面三句(/etc ...
- HDU 2067:小兔的棋盘
小兔的棋盘 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Subm ...
- StringBuffer中的flush()方法作用
在java API1.6对flush()方法的介绍如下: 方法摘要 void close() 关闭此流,但要先刷新它. void flush() 刷新该流的 ...
- volatile关键字解析
转载:http://www.cnblogs.com/dolphin0520/p/3920373.html volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受 ...
- 第五课 SharedPrefereneces
SharedPreferences总结: 一.SharedPreferences特点 1.本质是基于xml文件储存key-value对数据: 2.SharedPreferences对象本身只能获取数据 ...
- Runtime运行时的那点事儿
注:本文是对 Colin Wheeler 的 Understanding the Objective-C Runtime 的翻译. 初学 Objective-C(以下简称ObjC) 的人很容易忽略一个 ...
- .Net文件上传--小数据--un
文件上传控件:FileUpload - 控件,界面+方法+属性Button/LinkButton/ImageButton FileUpload控件:1.SaveAs("要上传到服务器的绝对路 ...