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( ...
随机推荐
- xib托线出来的为什么是weak而不是strong
因为控件他爹( view.superview )已经揪着它的小辫了( strong reference ),你( viewController )眼瞅着( weak reference )就好了. 当 ...
- win7下80端口被(Pid=4)占用的解决方法
首先介绍一种网上普遍的方法,就是查找占据80端口的进程,然后关闭它就行了. 1.运行cmd,然后输入netstat -a -n -o,回车:2.查看开头几行包含0.0.0.0:80的那一行最后的pid ...
- openlayers 学习笔记一
1. 创建地图,加载控件 var map = new OpenLayers.Map("map", { projection: new OpenLayers.Projection(& ...
- 给我发邮件(qq)| 和我联系
qq邮箱开放平台(只能是qq对qq): 简单点的发邮件: 和我联系
- android5.x以上 状态栏透明的问题
1.先在style中把 statusBarColor 设置为透明 如下 <item name="android:statusBarColor">@android:co ...
- Android 静默安装
有时候我们需要软件实现静默安装,但是Android并未提供相应的API,然而我们知道命令行安装android的时候是不会提示用户的,所有要实现这个功能,我们就可以从执行命令行的方式实现.android ...
- JAVA基础知识之JVM-——类加载器
类加载器负责将.class文件加载到内存,并为其创建java.lang.Class对象,这个对象就代表这个类. 在Java中,通过包名+类名来唯一标识一个类,而在JVM中,要用 类加载器实例+包名+类 ...
- python爬虫之Scrapy 使用代理配置
转载自:http://www.python_tab.com/html/2014/pythonweb_0326/724.html 在爬取网站内容的时候,最常遇到的问题是:网站对IP有限制,会有防抓取功能 ...
- 浅谈MySQL索引背后的数据结构及算法(转载)
转自:http://blogread.cn/it/article/4088?f=wb1 摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储 ...
- Web项目后台测试流程
1. 本地下载项目源码 1. Git clone项目代码到本地(本地项目代码1)并fetch: 2. Switch到master分支: 3. Create测试分支(例如:test1)并勾选“Switc ...