题意: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. 20145227《Java程序设计》第2次实验报告

    20145227<Java程序设计>第2次实验报告 实验步骤与内容 一.实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 ...

  2. redis 几种数据类型往数据库存数据和取数据的帮助类

    package com.fndsoft.bcis.utils; import org.springframework.beans.factory.annotation.Autowired; impor ...

  3. 修改sql2005字段

    alter table 表名 add 字段名 数据类型 default 默认值 增加:alter table AdCategory ADD SEOTitleNo varchar(50); 删除:ALT ...

  4. YTU 2972: C语言习题5.24--文件操作1

    2972: C语言习题5.24--文件操作1 时间限制: 1 Sec  内存限制: 128 MB 提交: 248  解决: 94 题目描述 文本文件score.dic 中存储了n名学生的信息(班级编号 ...

  5. Buy Tickets

    Buy Tickets Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 16010 Accepted: 7983 Descript ...

  6. gcc/g++动态链接库和静态库的链接顺序

    转自:http://withc8212.blog.163.com/blog/static/11656983820109263562854/ so文件:动态库a文件: 静态库exe文件:可执行程序(li ...

  7. tensorflow安装

    Ubuntu安装tensorflow先安装python-dev,再安装tensorflow就好了$ sudo apt-get install python-dev$ pip install https ...

  8. LAMMP架构的企业级应用

    LAMMP架构的企业级应用 ========================================= LAMMP是什么 LAMMP的实现 LAMMP适用的生产环境 ============= ...

  9. BZOJ 3534 重建

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3534 题意:给定一个无向图,每条边有选择概率P:求选出的边恰是一棵生成树的概率. 思路: ...

  10. jquery之each()、$.each()[jQuery.each()]

    导航: 1,jQuery对象(实例)的each()函数 2,全局jQuery对象的each()函数 一:jQuery对象(实例)的each()函数 each()函数用于以当前jQuery对象匹配到的每 ...