题意: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为根的子树后的直径

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define X first
  4 #define Y second
  5 #define pii pair<int, int>
  6 #define mp make_pair
  7 typedef long long ll;
  8 const int N = 1e5+5;
  9 void gmax(int& a, int b){ if(a < b) a = b;}
 10 int n;
 11 ll ans;
 12 int down[N][2], up[N], dis[N], dis2[N];
 13
 14 int head[N], nex[N*2], tot;
 15 pii edge[N*2];
 16 void init(){
 17     tot = 0;
 18     memset(head, -1, sizeof(head));
 19     memset(down, 0, sizeof(down));
 20     memset(up, 0, sizeof(up));
 21     memset(dis, 0, sizeof(dis));
 22     memset(dis2, 0, sizeof(dis2));
 23 }
 24 void add(int u, int v, int w){
 25     edge[tot] = mp(v, w);
 26     nex[tot] = head[u];
 27     head[u] = tot++;
 28 }
 29 //down[][0]:从i结点向下的最大距离
 30 //down[][1]:与down[][0]无交集的向下次大距离
 31 //dis:以i为根的子树的直径
 32 void dfs(int fa, int x){
 33 //    printf("dfs x %d, fa %d\n", x, fa);
 34 //down[x][0] = down[x][1] = dis[x] = dis2[x] = up[x] = 0;
 35     for(int i = head[x]; ~i; i = nex[i]){
 36         int y = edge[i].X, w = edge[i].Y;
 37         if(y == fa) continue ;
 38         dfs(x, y);
 39         if(down[y][0]+w > down[x][0])
 40             down[x][1] = down[x][0], down[x][0] = down[y][0]+w;
 41         else if(down[y][0]+w > down[x][1])
 42             down[x][1] = down[y][0]+w;
 43         gmax(dis[x], dis[y]);
 44     }
 45     gmax(dis[x], down[x][0]+down[x][1]);
 46 }
 47 //up:从i结点向上的最远距离
 48 //dis2:切掉以i为根的子树后的直径
 49 multiset<int>::iterator it;
 50 void dfs2(int fa, int x){
 51     if(fa != -1) ans += max(dis[x], dis2[x]);
 52 //    printf("fa %d, x %d\n", fa, x);
 53     multiset<int> se, se2;//兄弟树的直径, x往各个兄弟树的最长路
 54     for(int i = head[x]; ~i; i = nex[i]){
 55         int y = edge[i].X, w = edge[i].Y;
 56         if(y == fa) continue ;
 57         se.insert( dis[y] );
 58         se2.insert( down[y][0]+w );
 59     }
 60     for(int i = head[x]; ~i; i = nex[i]){
 61         int y = edge[i].X, w = edge[i].Y;
 62         if(y == fa) continue ;
 63         up[y] = up[x]+w;
 64         if(down[y][0]+w == down[x][0])
 65             gmax(up[y], down[x][1]+w);
 66         else gmax(up[y], down[x][0]+w);
 67         it = se.find( dis[y] ), se.erase(it);
 68         it = se2.find( down[y][0]+w ), se2.erase(it);
 69         dis2[y] = dis2[x];
 70         if(!se.empty())
 71             gmax(dis2[y], *se.rbegin());
 72         if(se2.empty()) gmax(dis2[y], up[x]);
 73         else gmax(dis2[y], up[x]+*se2.rbegin());
 74         if(se2.size() >= 2){
 75             int tmp = 0;
 76             it = se2.end();
 77             tmp += *--it;
 78             tmp += *--it;
 79             gmax(dis2[y], tmp);
 80         }
 81         dfs2(x, y);
 82         se.insert( dis[y] );
 83         se2.insert( down[y][0]+w );
 84     }
 85 }
 86 void debug(int n){
 87     for(int i = 1; i <= n; i++)
 88         printf("%d: down0 %d, down1 %d, dis %d, dis2 %d, up %d\n", i, down[i][0], down[i][1], dis[i], dis2[i], up[i]);
 89 }
 90 int main(){
 91     int t, u, v, w; scanf("%d", &t);
 92     while(t--) {
 93         init();
 94         scanf("%d", &n);
 95         for(int i = 1; i < n; i++){
 96             scanf("%d%d%d", &u, &v, &w);
 97             add(u, v, w), add(v, u, w);
 98         }
 99         ans = 0;
100         dfs(-1, 1);
101         dfs2(-1, 1);
102         printf("%lld\n", ans);
103     }
104     return 0;
105 }

View Code

解法二:

先求出原树的直径。

从直径两端分别来一次dp

切的边不在直径上,价值为直径;

切的边在直径上,由直径两端的dp得解。

转载于:https://www.cnblogs.com/dirge/p/5975794.html

HDU5886 Tower Defence 【两遍树形dp】【最长链预处理】相关推荐

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

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

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

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

  3. BZOJ 1040 ZJOI2008 骑士 树形DP

    题目大意:给定一个基环树林,每一个点上有权值,要求选择一个权值和最大的点集,要求点集中的随意两个点之间不能直接相连 最大点独立集--考虑到n<=100W,网络流铁定跑不了,于是我们考虑树形DP ...

  4. BZOJ 2878: [Noi2012]迷失游乐园( 树形dp )

    一棵树的话直接树形dp(求出往下走和往上走的期望长度). 假如是环套树, 环上的每棵树自己做一遍树形dp, 然后暴力枚举(环上的点<=20)环上每个点跑经过环上的路径就OK了. -------- ...

  5. CodeForces - 1324F Maximum White Subtree(树形dp)

    题目链接:点击查看 题目大意:给出 n 个点组成的树,每个点都有一个颜色,非黑即白,现在问对于每个点而言,选出一个连通块,使得白色点的个数与黑色点的个数做差最大 题目分析:记录一下div3的第一次ak ...

  6. 『树形DP·换根法』Accumulation Degree

    题目描述 有一个树形的水系,由 N-1 条河道和 N 个交叉点组成. 我们可以把交叉点看作树中的节点,编号为 1~N,河道则看作树中的无向边. 每条河道都有一个容量,连接 x 与 y 的河道的容量记为 ...

  7. BZOJ 3611 [Heoi2014]:虚树+树形DP

    时空隧道 今天考试T3正解是虚树-..(看到这个名字我好虚啊-.) 现在我们需要处理一棵树上k个点的询问,做一遍树形DP-- 复杂度是O(n)的,q个询问,感觉复杂度很爆炸-..>_<-- ...

  8. hdu 5886 Tower Defence 树形期望dp 雪漫防守战

    题意: 风暴斗篷现在要攻打雪漫城.雪漫城有n(n≤100000)个哨塔防守,哨塔之间有n-1条路相连,(构成一棵树).现在预测到风暴斗篷要进攻某一条路,然后这棵树就一分为二,现在要得到分开后的最长路. ...

  9. 动态规划(树形DP):HDU 5886 Tower Defence

    Sample Input 2 3 2 1 2 3 2 5 5 2 1 7 3 1 7 4 2 5 5 2 6 Sample Output 7 63 这类题目就是分类讨论,需要多做做. 1 #inclu ...

最新文章

  1. Java 抖音授权登录
  2. C++ Primer 5th笔记(chap 17 标准库特殊设施)流随机访问
  3. php变量与数组相互转换的方法(extract与compact
  4. 【转】[Java] HashMap使用的示例
  5. NET Core微服务之路:SkyWalking+SkyApm-dotnet分布式链路追踪系统的分享
  6. 要男女朋友有什么用?
  7. 在Junit上使用Kafka
  8. 谷歌:CNN击败Transformer,有望成为预训练界新霸主!LeCun却沉默了...
  9. SpringBoot 精通系列-SpringBoot如何操作Memcache
  10. 服务器虚拟机系统镜像安装win7系统,在虚拟机中怎么安装Win7旗舰版系统
  11. CAP迷思:关于分区容忍性
  12. 【黑客故事】钢铁侠Musk的音影记录
  13. Git详解之六:Git工具
  14. 30分钟扫描一亿行代码库,bug漏洞都能找,这款Facebook神器黑粉都赞叹不已
  15. 宁波诺丁汉计算机博士学费,宁诺1600万元博士奖学金开放申请 PhD scholarships open for application...
  16. python写论文难吗_师兄一年发表5篇CSSCI,原来高手也用套路……
  17. 学校计算机大赛的工作总结,工作总结之中国大学生计算机设计大赛参赛经验与总结...
  18. ijk的那些事(一)编译项目
  19. 手机联系人不见了怎么恢复?简单的恢复方法
  20. Python运行速度慢怎么办?

热门文章

  1. java停车管理系统中期检查_java毕业设计_springboot框架的停车场收费管理系统
  2. php集成paypal付款流程,在PHP中集成PayPal标准支付
  3. linux mysql统计次数_MySQL统计函数记录
  4. php定义常量mypi 3.14,php – Codeigniter 3使用未定义的常量VIEWPATH – 假设’VIEWPATH’...
  5. java的listroots_list(), listFiles(), listRoots() in Java
  6. android 停用应用的命令,免Root使用ADB命令_停用手机系统应用
  7. data的值 如何初始化vue_vue data恢复初始化数据的实现方法
  8. 3dmax材质通道插件_为什么3dmax插件这么多都不会整合一下呢?
  9. python中的逻辑运算符and和or
  10. lasTools laszip.exe 点云las/laz的无损压缩/解压缩工具