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为根的子树后的直径
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】【最长链预处理】相关推荐
- 洛谷 P1352 没有上司的舞会【树形DP/邻接链表+链式前向星】
题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...
- 洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)
洛谷题目传送门 ZJOI的考场上最弱外省选手T2 10分成功滚粗...... 首先要想到30分的结论 说实话Day1前几天刚刚刚掉了SDOI2017的树点涂色,考场上也想到了这一点 想到了又有什么用? ...
- BZOJ 1040 ZJOI2008 骑士 树形DP
题目大意:给定一个基环树林,每一个点上有权值,要求选择一个权值和最大的点集,要求点集中的随意两个点之间不能直接相连 最大点独立集--考虑到n<=100W,网络流铁定跑不了,于是我们考虑树形DP ...
- BZOJ 2878: [Noi2012]迷失游乐园( 树形dp )
一棵树的话直接树形dp(求出往下走和往上走的期望长度). 假如是环套树, 环上的每棵树自己做一遍树形dp, 然后暴力枚举(环上的点<=20)环上每个点跑经过环上的路径就OK了. -------- ...
- CodeForces - 1324F Maximum White Subtree(树形dp)
题目链接:点击查看 题目大意:给出 n 个点组成的树,每个点都有一个颜色,非黑即白,现在问对于每个点而言,选出一个连通块,使得白色点的个数与黑色点的个数做差最大 题目分析:记录一下div3的第一次ak ...
- 『树形DP·换根法』Accumulation Degree
题目描述 有一个树形的水系,由 N-1 条河道和 N 个交叉点组成. 我们可以把交叉点看作树中的节点,编号为 1~N,河道则看作树中的无向边. 每条河道都有一个容量,连接 x 与 y 的河道的容量记为 ...
- BZOJ 3611 [Heoi2014]:虚树+树形DP
时空隧道 今天考试T3正解是虚树-..(看到这个名字我好虚啊-.) 现在我们需要处理一棵树上k个点的询问,做一遍树形DP-- 复杂度是O(n)的,q个询问,感觉复杂度很爆炸-..>_<-- ...
- hdu 5886 Tower Defence 树形期望dp 雪漫防守战
题意: 风暴斗篷现在要攻打雪漫城.雪漫城有n(n≤100000)个哨塔防守,哨塔之间有n-1条路相连,(构成一棵树).现在预测到风暴斗篷要进攻某一条路,然后这棵树就一分为二,现在要得到分开后的最长路. ...
- 动态规划(树形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 ...
最新文章
- Java 抖音授权登录
- C++ Primer 5th笔记(chap 17 标准库特殊设施)流随机访问
- php变量与数组相互转换的方法(extract与compact
- 【转】[Java] HashMap使用的示例
- NET Core微服务之路:SkyWalking+SkyApm-dotnet分布式链路追踪系统的分享
- 要男女朋友有什么用?
- 在Junit上使用Kafka
- 谷歌:CNN击败Transformer,有望成为预训练界新霸主!LeCun却沉默了...
- SpringBoot 精通系列-SpringBoot如何操作Memcache
- 服务器虚拟机系统镜像安装win7系统,在虚拟机中怎么安装Win7旗舰版系统
- CAP迷思:关于分区容忍性
- 【黑客故事】钢铁侠Musk的音影记录
- Git详解之六:Git工具
- 30分钟扫描一亿行代码库,bug漏洞都能找,这款Facebook神器黑粉都赞叹不已
- 宁波诺丁汉计算机博士学费,宁诺1600万元博士奖学金开放申请 PhD scholarships open for application...
- python写论文难吗_师兄一年发表5篇CSSCI,原来高手也用套路……
- 学校计算机大赛的工作总结,工作总结之中国大学生计算机设计大赛参赛经验与总结...
- ijk的那些事(一)编译项目
- 手机联系人不见了怎么恢复?简单的恢复方法
- Python运行速度慢怎么办?
热门文章
- java停车管理系统中期检查_java毕业设计_springboot框架的停车场收费管理系统
- php集成paypal付款流程,在PHP中集成PayPal标准支付
- linux mysql统计次数_MySQL统计函数记录
- php定义常量mypi 3.14,php – Codeigniter 3使用未定义的常量VIEWPATH – 假设’VIEWPATH’...
- java的listroots_list(), listFiles(), listRoots() in Java
- android 停用应用的命令,免Root使用ADB命令_停用手机系统应用
- data的值 如何初始化vue_vue data恢复初始化数据的实现方法
- 3dmax材质通道插件_为什么3dmax插件这么多都不会整合一下呢?
- python中的逻辑运算符and和or
- lasTools laszip.exe 点云las/laz的无损压缩/解压缩工具