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个数的前缀和 ...
随机推荐
- IOCP陷阱
1. AcceptEx 10061 客户端循环连接,没有发送数据,一定次数后,连接失败,WSAGetLastError的结果是10061.并且后续无法再次连接. 这是因为其中的一个参数,详细用法参考I ...
- java IO流读取图片供前台显示
最近项目中需要用到IO流来读取图片以提供前台页面展示,由于以前一直是用url路径的方式进行图片展示,一听说要项目要用IO流读取图片感觉好复杂一样,但任务下达下来了,做为程序员只有选择去执行喽,于是找了 ...
- SQL Server表 & 存储过程 创建日期查询
查询表创建时间 SELECT [name] ,create_date ,modify_date FROM sys.tables ORDER BY modify_date DESC 查下存储过程创建时间 ...
- 在Github或Gitee上用hexo搭建个人博客
安装nodejs环境查看node版本node -v 安装cnpmnpm install cnpm -g --registry=https://registry.npm.taobao.org 安装 He ...
- 【VS开发】【C/C++开发】关于boost库的C++11导致的undefined符号问题
undefined reference to boost::program_options::options_description::m_default_line_length 问题最终解决依靠的是 ...
- Python 绘制 柱状图
用Python 绘制 柱状图,使用的是bar()函数. 一个简单的例子: # 创建一个点数为 8 x 6 的窗口, 并设置分辨率为 80像素/每英寸 plt.figure(figsize=(10, 1 ...
- Plsql 破解 非密钥版
打开注册表在run下输入regedit删除1.HKEY_CURRENT_USER/Software/Allround Automations2.HKEY_CURRENT_USER/Software/M ...
- thinkphp的路径问题
无法加载模块?验证码无法显示?__URL__没有替换成当前模块路径?那么你可能遇到了跟我一样的问题.如果你是通过超链接(或者是在地址栏输入该页面的地址)来访问某个页面(即模版)时,如果你在这个页面使用 ...
- JS异步操作概述(转)
add by zhj: 只转载了一部分.异步操作的三种模式未转载,因为里面代码比较多,复制过来麻烦 原文:https://wangdoc.com/javascript/async/general.ht ...
- SSRS连接ORACLE数据库制作报表
SSRS报表基于ORACLE数据库做报表示例. 开发环境:VS2010 SQL SERVER 数据库:SQL SERVER 2012 PS:数据库连接部分可能有还有个问题就是ORACLE数据源这一部分 ...