2019年杭电多校第三场 1011题Squrirrel(HDU6613+树DP)
题目链接
题意
给你一棵无根树,要你寻找一个根节点使得在将一条边权变为\(0\)后,离树根最远的点到根节点的距离最小。
思路
本题和求树的直径很像,不过要记得的东西有点多,且状态也很多。
\(fi[u][0]\)表示在\(u\)这个结点不删边沿着子树方向能到达的最远距离,\(se[u][0]\)为第二远,\(th[u][0]\)为第三远,\(fa[u][0]\)表示沿着父亲方向能到达的最远距离,第二维为\(1\)表示删一条边能到达的距离。
不删边的转移和求树的直径转移方程基本上是一样的,就不再说明。
首先从以\(u\)为根的子树中删除一条边,能到达的最远距离的最小值为\(fi[u][1]=min(fi[v][0],max(fi[v][1],se[v][0])+w)\),\(v\)为\(u\)沿着\(v\)往子树方向走是最远的,也就是说它有三种状态:
- 删除与\(v\)连接的边能到达的最远距离,在\(u\)的所有儿子结点中,你不删与\(v\)相连的边而删其他的边,那么从子树方向能到达的最远距离仍然是最远距离,不会产生任何影响,肯定不是最优解。
- 不删除与\(v\)连接的边而在以\(v\)为根的子树中删除一条边能到达的最远距离,注意删除了最远距离的路径上的一条边后原来的次远距离可能变成了最远距离。
次远距离的最小值一样的转移方法,至于对于\(u\)在删除一条边后\(fi[u][1]\)与\(se[u][0]\)的大小关系我们暂时先不考虑。
上面的转移方程只能处理从子树方向的转移,却不能处理沿着父亲结点方向能到达的最远距离,因此我们需要再进行一次\(dfs\)来进行状态转移。
假设当前已经处理出了父亲结点\(u\)沿着其父亲结点在不删边的情况下不沿着\(v\)这个方向所能到达的最远距离\(fa[u][0]\)和删边的最远距离\(fa[u][1]\),那么子结点\(v\)沿着\(u\)所能到达的最远距离的转移:
- 当\(v\)走是\(u\)沿着子树走能到达的最远距离,那么\(fa[v][0]=max(fa[u][0],se[u][0])+w\),也就是从\(u\)沿着其父亲结点所能到达的最远距离与沿着其子结点所能到达的次远距离两者中最远的转移过来。\(fa[v][1]=min(max(fa[u][0], se[u][0]), min(max(fa[u][1], se[u][0]), max(fa[u][0], max(se[u][1], th[u][0]))) + ed[i].w)\),删除\(u,v\)之间的边所能到达的最远距离与不删除\(u,v\)之间的边所能到达的最远距离,因为删除一条边之后次远距离并不一定比第三远的距离远因此这两者之间也要取个\(max\)。
- 当\(v\)走是\(u\)沿着子树走能到达的次远、第三远的转移方程和原理类似。
代码实现如下
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("D://Code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)
const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 2e5 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
int t, n, tot, u, v, w, ans, idx;
int head[maxn], fa[maxn][3], d[maxn];
int idx1[maxn], idx2[maxn], idx3[maxn];
int fi[maxn][3], se[maxn][3], th[maxn][3];
struct edge {
int v, w, next;
}ed[maxn*2];
void add(int u, int v, int w) {
ed[tot].v = v;
ed[tot].w = w;
ed[tot].next = head[u];
head[u] = tot++;
}
void dfs1(int u, int p) {
for(int i = head[u]; ~i; i = ed[i].next) {
int v = ed[i].v;
if(v == p) continue;
dfs1(v, u);
d[v] = ed[i].w;
if(fi[v][0] + ed[i].w > fi[u][0]) {
th[u][0] = se[u][0];
idx3[u] = idx2[u];
se[u][0] = fi[u][0];
idx2[u] = idx1[u];
idx1[u] = v;
fi[u][0] = fi[v][0] + ed[i].w;
} else if(fi[v][0] + ed[i].w > se[u][0]) {
th[u][0] = se[u][0];
idx3[u] = idx2[u];
se[u][0] = fi[v][0] + ed[i].w;
idx2[u] = v;
} else if(fi[v][0] + ed[i].w > th[u][0]) {
th[u][0] = fi[v][0] + ed[i].w;
idx3[u] = v;
}
}
fi[u][1] = min(fi[idx1[u]][0], max(fi[idx1[u]][1], se[idx1[u]][0]) + d[idx1[u]]);
se[u][1] = min(fi[idx2[u]][0], max(fi[idx2[u]][1], se[idx2[u]][0]) + d[idx2[u]]);
}
void dfs2(int u, int p) {
int tmp = min(max(fa[u][1], fi[u][0]), max(fa[u][0], max(fi[u][1], se[u][0])));
if(tmp < ans) ans = tmp, idx = u;
else if(tmp == ans && u < idx) ans = tmp, idx = u;
for(int i = head[u]; ~i; i = ed[i].next) {
int v = ed[i].v;
if(v == p) continue;
if(idx1[u] == v) {
fa[v][0] = max(fa[u][0], se[u][0]) + ed[i].w;
fa[v][1] = min(max(fa[u][0], se[u][0]), min(max(fa[u][1], se[u][0]), max(fa[u][0], max(se[u][1], th[u][0]))) + ed[i].w);
} else {
fa[v][0] = max(fa[u][0], fi[u][0]) + ed[i].w;
if(idx2[u] == v) {
fa[v][1] = min(max(fa[u][0], fi[u][0]), min(max(fa[u][1], fi[u][0]), max(fa[u][0], max(fi[u][1], th[u][0]))) + ed[i].w);
} else {
fa[v][1] = min(max(fa[u][0], fi[u][0]), min(max(fa[u][1], fi[u][0]), max(fa[u][0], max(fi[u][1], se[u][0]))) + ed[i].w);
}
}
dfs2(v, u);
}
}
int main() {
#ifndef ONLINE_JUDGE
FIN;
#endif // ONLINE_JUDGE
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
tot = 0;
for(int i = 1; i <= n; ++i) {
head[i] = -1;
d[i] = idx1[i] = idx2[i] = idx3[i] = 0;
for(int j = 0; j < 2; ++j) {
fi[i][j] = se[i][j] = th[i][j] = fa[i][j] = 0;
}
}
for(int i = 1; i <= n - 1; ++i) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
dfs1(1, 0);
ans = inf, idx = 1;
dfs2(1, 0);
printf("%d %d\n", idx, ans);
}
return 0;
}
2019年杭电多校第三场 1011题Squrirrel(HDU6613+树DP)的更多相关文章
- 2019年杭电多校第三场 1008题Game(HDU6610+带修改莫队+Nim博弈)
题目链接 传送门 题意 给你\(n\)堆石子,每堆有\(a_i\)堆石子,\(q\)次操作: 在\([L,R]\)内有多少个子区间使得\(Alice\)(先手)在\(Nim\)博弈中获胜: 交换\(a ...
- Make Rounddog Happy(2019年杭电多校第十场1011+HDU6701+启发式分治)
目录 题目链接 题意 思路 代码 题目链接 传送门 题意 求有多少个子区间满足\(a_l,a_{l+1},\dots,a_r\)均不相同且\(max(a_l,a_{l+1},\dots,a_r)-(r ...
- 可持久化线段树的学习(区间第k大和查询历史版本的数据)(杭电多校赛第二场1011)
以前我们学习了线段树可以知道,线段树的每一个节点都储存的是一段区间,所以线段树可以做简单的区间查询,更改等简单的操作. 而后面再做有些题目,就可能会碰到一种回退的操作.这里的回退是指回到未做各种操作之 ...
- [2019杭电多校第三场][hdu6609]Find the answer(线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6609 大致题意是求出每个位置i最小需要将几个位置j变为0(j<i),使得$\sum_{j=1}^ ...
- [2019杭电多校第三场][hdu6608]Fansblog
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6608 大致题意是比p小的最大素数q,求q!%p的值. 由威尔逊定理开始推: $(p-1)!\equiv ...
- [2019杭电多校第三场][hdu6606]Distribution of books(线段树&&dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6606 题意为在n个数中选m(自选)个数,然后把m个数分成k块,使得每块数字之和最大的最小. 求数字和最 ...
- 2019杭电多校第三场hdu6608 Fansblog(威尔逊定理)
Fansblog 题目传送门 解题思路 Q! % P = (P-1)!/(P-1)...(Q-1) % P. 因为P是质数,根据威尔逊定理,(P-1)!%P=P-1.所以答案就是(P-1)((P-1) ...
- 2019杭电多校第三场hdu6609 Find the answer(线段树)
Find the answer 题目传送门 解题思路 要想变0的个数最少,显然是优先把大的变成0.所以离散化,建立一颗权值线段树,维护区间和与区间元素数量,假设至少减去k才能满足条件,查询大于等于k的 ...
- 2019杭电多校第三场hdu6606 Distribution of books(二分答案+dp+权值线段树)
Distribution of books 题目传送门 解题思路 求最大值的最小值,可以想到用二分答案. 对于二分出的每个mid,要找到是否存在前缀可以份为小于等于mid的k份.先求出这n个数的前缀和 ...
随机推荐
- JUC锁框架_AbstractQueuedSynchronizer详细分析
AQS是JUC锁框架中最重要的类,通过它来实现独占锁和共享锁的.本章是对AbstractQueuedSynchronizer源码的完全解析,分为四个部分介绍: CLH队列即同步队列:储存着所有等待 ...
- windows7 安装 docker-compose
这篇博客,默认你已经安装了docker,下面介绍如何安装docker-compose 1.访问docker-compose的git地址 2.找到最新版的docker-compose 3.打开Docke ...
- CentOS 7下JumpServer安装及配置
环境 系统 # cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) # uname -r 3.10.0-693.21.1.el7. ...
- PHP生成正则表达式的类
正则表达式,写起来还是比较费劲的,于是封装个类,初稿,抛砖引玉. 关于正则,建议参考 https://github.com/CyC2018/CS-Notes/blob/master/notes/%E6 ...
- BBC micro:bit引脚介绍
另外两个大引脚(3V和GND)是非常不同的! 注意 标记为3V和GND的引脚与电路板的电源相关,千万不要连接在一起. 电源输入:如果BBC micro:bit由USB或电池供电,则可以使用3V引脚作为 ...
- unity文件路径
转载自:https://blog.csdn.net/linxinfa/article/details/51679528 各平台具体路径: 1.Resources Resources文件夹是一个只读的文 ...
- Mysql 8.0版本开始,不允许创建 MyISAM 分区表
从MySQL 8.0版本开始,就不允许创建 MyISAM 分区表了,只允许创建已经实现了本地分区策略的引擎. 到目前为止,只有InnoDB和NDB这两个引擎支持本地分区策略. [1]实际测试 (1)数 ...
- 『正睿OI 2019SC Day1』
概率与期望 总结 老师上午几乎是在讲数学课,没有讲什么和\(OI\)有关的题目,所以我就做了一点笔记. 到了下午,老师讲完了有关知识点和经典模型,就开始讲例题了.前两道例题是以前就做过的,所以没有什么 ...
- SQL系列(四)—— 唯一值(distinct)
有时需要查询某列上的不重复的数据,如: SELECT name FROM student; 结果: name lxy lxy lxy lxy 这样的结果显然不符合我们的需求.如何对列数据进行去重,查询 ...
- 移动开发首页业界资讯移动应用平台技术专题 输入您要搜索的内容 基于Java Socket的自定义协议,实现Android与服务器的长连接(二)
在阅读本文前需要对socket以及自定义协议有一个基本的了解,可以先查看上一篇文章<基于Java Socket的自定义协议,实现Android与服务器的长连接(一)>学习相关的基础知识点. ...