题意: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】【最长链预处理】的更多相关文章

  1. 【树形dp 最长链】bzoj1912: [Apio2010]patrol 巡逻

    富有思维性的树形dp Description Input 第一行包含两个整数 n, K(1 ≤ K ≤ 2).接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, ...

  2. P3565 由简单的树形dp 引入 长链刨分

    这道题感觉不太行 因为自己没想出来. 先说一下暴力吧,取三个点 让两两之间的距离相等怎么做呢,看起来是很复杂的样子的,但是仔细观察发现 答案出自一个点的儿子之间 或者儿子和父亲之间. 暴力枚举三个点然 ...

  3. LOJ3053 十二省联考2019 希望 容斥、树形DP、长链剖分

    传送门 官方题解其实讲的挺清楚了,就是锅有点多-- 一些有启发性的部分分 L=N 一个经典(反正我是不会)的容斥:最后的答案=对于每个点能够以它作为集合点的方案数-对于每条边能够以其两个端点作为集合点 ...

  4. 洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)

    洛谷题目传送门 ZJOI的考场上最弱外省选手T2 10分成功滚粗...... 首先要想到30分的结论 说实话Day1前几天刚刚刚掉了SDOI2017的树点涂色,考场上也想到了这一点 想到了又有什么用? ...

  5. 洛谷 P1352 没有上司的舞会【树形DP/邻接链表+链式前向星】

    题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...

  6. HDU 4612 Warm up (边双连通分量+DP最长链)

    [题意]给定一个无向图,问在允许加一条边的情况下,最少的桥的个数 [思路]对图做一遍Tarjan找出桥,把双连通分量缩成一个点,这样原图就成了一棵树,树的每条边都是桥.然后在树中求最长链,这样在两端点 ...

  7. HDU 4607 Park Visit (DP最长链)

    [题目]题意:N个城市形成一棵树,相邻城市之间的距离是1,问访问K个城市的最短路程是多少,共有M次询问(1 <= N, M <= 100000, 1 <= K <= N). [ ...

  8. Codeforces Round #135 (Div. 2) D - Choosing Capital for Treeland(两种树形DP)

  9. BZOJ.2159.Crash的文明世界(斯特林数 树形DP)

    BZOJ 洛谷 挺套路但并不难的一道题 \(Description\) 给定一棵\(n\)个点的树和\(K\),边权为\(1\).对于每个点\(x\),求\(S(x)=\sum_{i=1}^ndis( ...

随机推荐

  1. 【PHP设计模式 02_JieKou.php】面向接口开发

    <?php /** * [面向接口开发] * */ header("Content-type: text/html; charset=utf-8"); /*共同接口--连接数 ...

  2. iOS开发- 蓝牙后台接收数据(BLE4.0)

    最近在做一个蓝牙相关的项目, 需要在应用进入后台, 或者手机属于锁屏状态的情况下, 仍然保持蓝牙连接, 并且能正常接收数据. 本来以后会很麻烦, 但是学习了下..发现就2步而已.简单的不能再简单了. ...

  3. pipe row的用法, Oracle split 函数写法.

    为了让 PL/SQL 函数返回数据的多个行,必须通过返回一个 REF CURSOR 或一个数据集合来完成.REF CURSOR 的这种情况局限于可以从查询中选择的数据,而整个集合在可以返回前,必须进行 ...

  4. nodepad + 插件

    Notepad++是一款Windows环 境下免费开源的代码编辑器,支持的语言: C, C++ , Java , C#, XML,SQL,Ada, HTML, PHP, ASP, AutoIt, 汇编 ...

  5. StringUtils中 isEmpty 和isBlank的区别

    StringUtils方法的操作对象是java.lang.String类型的对象,是JDK提供的String类型操作方法的补充,并且是null安全的(即如果输入参数String为null则不会抛出Nu ...

  6. Spring+Quartz实现定时执行任务的配置

    1.要想使用Quartz 必须要引入相关的包:以下是我在项目中gradle中的配置: compile 'org.quartz-scheduler:quartz:2.1.1' 2.Scheduler的配 ...

  7. Antenna Placement

    Antenna Placement Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7574 Accepted: 3762 Des ...

  8. python-day7 python内置模块 面向对象

    1.configparser模块 configparser用于处理特定格式的文件,其本质上是利用open来操作文件 # 注释1 ; 注释2 [section1] # 节点 k1 = v1 # 值 k2 ...

  9. CurrentHashMap的实现原理

    转载:http://wiki.jikexueyuan.com/project/java-collection/concurrenthashmap.html 概述 我们在之前的博文中了解到关于 Hash ...

  10. Multi-Perspective Sentence Similarity Modeling论文demo实现

    由于下载glove时,下载脚本并未自己执行txt文件转.th文件,在执行th trainSIC.lua时报错 需要根据fetch_and_preprocess.sh中的代码利用scripts中的con ...