[TJOI2017]城市
嘟嘟嘟
这题刚开始想复杂了,想什么dp去了,其实没那么难。
考虑断掉一条边,记分离出来的两棵子树为A和B,那么合并后的树的直径可能有三种情况:
1.A的直径。
2.B的直径
3.A的半径+边权+B的半径。
半径是啥?记从点\(i\)出发到树上任意一点的最长距离为\(f[i]\),则树的半径就是\(min \{ f[i] \}\)(此题需要min,严格定义我也不知道是max还是min)。
所以我们\(O(n)\)枚举断边,\(O(n)\)求树的直径和半径即可。
直径不必说,说一下怎么求半径。
对于点\(v\),记\(v\)的父亲为\(u\), \(v\)的半径有这么几种情况:
1.\(v\)子树内的最长链。
2.\(v\)子树外,\(u\)子树内的一条链 + \(dis(u, v)\)。
3.\(u\)子树外的最长链 + \(dis(u, v)\)。
对于情况1,求树的直径的时候就维护好了。
对于情况2,我们需要维护最长连和次长链。然后如果\(v\)在\(u\)的最长链上,就是\(u\)的次长链 + \(dis(u, v)\);否则就是\(u\)的最长链 + \(dis(u, v)\)。
对于情况3,在dfs的时候维护一个fro,表示\(u\)子树外的最长链,维护fro的时候也向情况2分两种情况,分别更新即可。
答案就是所以直径的min。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 5e3 + 5;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int n;
struct Node
{
int x, y, w;
}t[maxn];
struct Edge
{
int nxt, to, w;
}e[maxn << 1];
int head[maxn], ecnt = -1;
In void addEdge(int x, int y, int w)
{
e[++ecnt] = (Edge){head[x], y, w};
head[x] = ecnt;
}
bool col[maxn];
int dp1[maxn], dp2[maxn], dia_Max = 0;
In void dfs(int now, int _f, int c)
{
dp1[now] = 0, col[now] = c;
int Max1 = 0, Max2 = 0;
for(int i = head[now], v; ~i; i = e[i].nxt)
{
if((v = e[i].to) == _f) continue;
dfs(v, now, c);
if(dp1[v] + e[i].w > Max1) Max2 = Max1, Max1 = dp1[v] + e[i].w;
else if(dp1[v] + e[i].w > Max2) Max2 = dp1[v] + e[i].w;
}
dp1[now] = Max1; dp2[now] = Max2;
dia_Max = max(dia_Max, Max1 + Max2);
}
int f[maxn];
In void dfs2(int now, int _f, int fro)
{
int tp = 0;
for(int i = head[now], v; ~i; i = e[i].nxt)
{
if((v = e[i].to) == _f) continue;
if(dp1[v] + e[i].w == dp1[now])
{
f[v] = max(dp1[v], dp2[now] + e[i].w);
tp = max(dp2[now], fro);
}
else
{
f[v] = max(dp1[v], dp1[now] + e[i].w);
tp = max(dp1[now], fro);
}
f[v] = max(f[v], tp + e[i].w);
dfs2(v, now, tp + e[i].w);
}
}
int main()
{
Mem(head, -1);
n = read();
for(int i = 1; i < n; ++i)
{
int x = read(), y = read(), w = read();
t[i] = (Node){x, y, w};
addEdge(x, y, w), addEdge(y, x, w);
}
int ans = INF;
for(int i = 1; i < n; ++i)
{
dia_Max = 0;
dfs(t[i].x, t[i].y, 0), dfs(t[i].y, t[i].x, 1);
f[t[i].x] = dp1[t[i].x], f[t[i].y] = dp1[t[i].y];
dfs2(t[i].x, t[i].y, 0), dfs2(t[i].y, t[i].x, 0);
int pos1 = t[i].x, pos2 = t[i].y;
for(int j = 1; j <= n; ++j)
{
if(!col[j] && f[j] < f[pos1]) pos1 = j;
if(col[j] && f[j] < f[pos2]) pos2 = j;
}
ans = min(ans, max(dia_Max, f[pos1] + f[pos2] + t[i].w));
}
write(ans), enter;
return 0;
}
[TJOI2017]城市的更多相关文章
- 【BZOJ4890】[TJOI2017]城市(动态规划)
[BZOJ4890][TJOI2017]城市(动态规划) 题面 BZOJ 洛谷 题解 数据范围都这样了,显然可以暴力枚举断开哪条边. 然后求出两侧直径,暴力在直径上面找到一个点,使得其距离直径两端点的 ...
- [洛谷P3761] [TJOI2017]城市
洛谷题目链接:[TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速 ...
- 换根DP+树的直径【洛谷P3761】 [TJOI2017]城市
P3761 [TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公 ...
- bzoj4890[Tjoi2017]城市(树的半径)
4890: [Tjoi2017]城市 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 149 Solved: 91[Submit][Status][D ...
- [TJOI2017]城市(树的直径)
[TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公路相互可达, ...
- [BZOJ4890][TJOI2017]城市(DP)
题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公路相互可达,但是通过一条高速公路需要收 ...
- BZOJ4890 & 洛谷3761:[TJOI2017]城市——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4890 https://www.luogu.org/problemnew/show/P3761 从加 ...
- [TJOI2017]城市 【树的直径+暴力+优化】
Online Judge:Luogu P3761 Label:树的直径,暴力 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有n座城市,n-1条高速公路,保证了 ...
- luogu P3761 [TJOI2017]城市 树的直径 bfs
LINK:城市 谢邀,学弟说的一道毒瘤题. 没有真正的省选题目毒瘤 或者说 写O(n)的做法确实毒瘤. 这里给一个花20min就写完的非常好写的暴力. 容易想到枚举哪条边删掉 删掉之后考虑在哪两个点上 ...
随机推荐
- vim 学习笔记系列(前言)
今天上午的时候,看到大神在用vim编程,画面直观,速度很快,操作只需要用命令符就可以实施. 所以可以推断vim的命令符是复杂的,那么学习过程中记忆会很漫长,很痛苦,但是如果记住了这些命令符,并可以熟练 ...
- 搞清Image加载事件(onload)、加载状态(complete)后,实现图片的本地预览,并自适应于父元素内(完成)
onload与complete介绍 complete只是HTMLImageElement对象的一个属性,可以判断图片加载完成,不管图片是不是有缓存:而onload则是这个Image对象的load事件回 ...
- Apache Beam WordCount编程实战及源码解读
概述:Apache Beam WordCount编程实战及源码解读,并通过intellij IDEA和terminal两种方式调试运行WordCount程序,Apache Beam对大数据的批处理和流 ...
- Mysql 常用数据类型
double:浮点型,double(5,2) 表示最多5位,必须包含两位小数,最大值是 999.99 char:定长字符串类型,char(10) 表示必须放 10 的字节,没有就用空格补充 varch ...
- Loadrunner 脚本优化-事务函数简介
脚本优化-事务函数简介 by:授客 QQ:1033553122 1.事务的开始和结束名称需要相同 lr_start_transaction(“transaction_name”); …//事务处理 l ...
- Visual Studio未能加载“XX”包的解决方案
1.打开命令行(管理员) 2.进入到devenv.exe所在的目录u 3.输入devenv,会出现帮助提示 4.将所有带“Reset..”的命令执行一遍 5.OK 我尝试过使用修复功能,貌似没有作用. ...
- leetcode-977. 有序数组的平方
leetcode-977. 有序数组的平方 (来自 120周赛) 题意 给定一个按非递减顺序排序的整数数组 A,返回每个数字的平方组成的新数组,要求也按非递减顺序排序. 示例 1: 输入:[-4,-1 ...
- HDFS快速入门
一.简介 HDFS[Hadoop Distributed File System]是Hadoop组件中的分布式存储系统,提供高可靠性.高扩展性和高吞吐率的数据存储服务. 二.存储模型 1.文件线性切割 ...
- Spark SQL整体架构
0.整体架构 注意:Spark SQL是Spark Core之上的一个模块,所有SQL操作最终都通过Catalyst翻译成类似的Spark程序代码被Spark Core调度执行,其过程也有Job.St ...
- 洗礼灵魂,修炼python(79)--全栈项目实战篇(7)—— 多级目录菜单之地址管理系统升级版
要求: 1.在上一篇的地址管理系统的基础上做升级改动 2.添加增删改的功能 3.尽量的贴近生活常识中的地址管理 分析: 需求不用多说了,干就完了 相关文件源码地址:github 这次由于要有增删改的操 ...