【CodeForces】835F Roads in the Kingdom
一、题目
题目描述
王国有\(n\)座城市与\(n\)条有长度的街道,保证所有城市直接或间接联通,我们定义王国的直径为所有点对最短距离中的最大值,现因财政危机需拆除一条道路并同时要求所有城市仍然联通,求所有拆除方案中王国直径的最小值
输入格式
第一行一个整数\(n\),接下来\(n\)行每行三个整数\(u,v,w\)表示城市\(u,v\)之间有一条长度为\(w\)的道路
输出格式
一行一个答案,表示所有方案中直径最小值
二、题意
定义直径为任意两点间的最短距离的最大值。给出一棵基环树,问删去环上的一条边,使剩下的树的直径最小。问最小的直径是多少。
三、PROCESS OF THINKING
我刚开始的时候在想怎么选择删的边才最优,后来想了一个上午发现好像行不通。所以我往枚举删除哪条边,然后快速求出此时的树的直径这方面想。
其中有一点可以确定,就是每个环上的点对应的树是不变的。
应该可以想到求出每个环上的点到其树中的最长链。然后通过环来合并这些链。
考虑环上的点,首先我们枚举只能从\(x\)开始顺时针走(相当于把\(x\)连向前面的点的边删掉)。设\(f_i\)为\(i\)这个点对应的链长,\(sum_i\)为\(i\)到\(x\)的距离。
由此可以得出一条路径可以表示为$$f_i+f_j+sum_j-sum_i$$,即为$$f_i-sum_i+sum_j+f_j$$。
而对于每种情况我们要求的是最长的路径。故只要\(f_i-sum_i\)最大,\(f_j+sum_j\)最大就行了。用两个set维护就好了。
至于万一选择的两个点\(i\),\(j\)的相对位置的问题,我也思考了一下(可能是我太弱了)。
我们假设\(i\)在\(j\)后面,而我们选择了\(i\)是\(f_i+sum_i\)最大的,\(j\)是\(f_j-sum_j\)最大的。那么由于\(sum_i>sum_j\),所以其实$$f_i+sum_i+f_j-sum_j>f_i-sum_i+f_j+sum_j$$的。(哦,这里提一下,如果选择的\(i=j\),那么尝试\(f_i+sum_i\)取次小值,或\(f_j-sum_j\)取次小值)所以我们只要保证\(f_i+sum_i+f_j-sum_j\)是最优的且\(i\not=j\),一定可以保证\(i\)在\(j\)前面。
这里还有一个小细节,就是如何枚举下一个开始点时,要把上一个点\(i\)放到数组的末尾,还要解决\(sum_i\)变大的问题。其实只要把环上的点再重新加到原数组的末尾就好了,这样可以解决\(sum_i\)的问题。
四、代码
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair <LL, int> PLI;
typedef pair <int, int> PII;
const int MAXN = 200000;
const LL INF = 1e15;
multiset <PLI, greater <PLI> > set1;
multiset <PLI, greater <PLI> > set2;
struct Edge {
int to, nxt, w;
} edge[MAXN + 5 << 1];
LL ans, mxdis[MAXN + 5], sum[MAXN + 5 << 1], dia;
int fir[MAXN + 5], ecnt, pre[MAXN + 5], eid[MAXN + 5], lpcnt, dfn[MAXN + 5], timer, n;
PII lop[MAXN + 5 << 1];
bool inl[MAXN + 5];
template <typename T> void read(T &x) {
x = 0; int f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - 48; c = getchar(); }
x *= f;
}
void addedge(int u, int v, int w) {
edge[++ecnt].to = v;
edge[ecnt].nxt = fir[u];
edge[ecnt].w = w;
fir[u] = ecnt;
}
void getloop(int u) {
dfn[u] = ++timer;
for (int e = fir[u]; e && !lpcnt; e = edge[e].nxt) {
int v = edge[e].to;
if (v == pre[u]) continue;
if (dfn[v]) {
if (dfn[v] < dfn[u]) continue;
for (int i = v; i != u; i = pre[i]) {
lop[++lpcnt] = make_pair(i, edge[eid[i]].w);
inl[i] = true;
}
lop[++lpcnt] = make_pair(u, edge[e].w);
inl[u] = true;
return;
}
pre[v] = u;
eid[v] = e;
getloop(v);
}
}
void dfs(int u, int fa) {
LL maxx = 0, minx = 0;
mxdis[u] = 0;
for (int e = fir[u]; e; e = edge[e].nxt) {
int v = edge[e].to;
if (v == fa || inl[v]) continue;
dfs(v, u);
mxdis[u] = max(mxdis[u], mxdis[v] + edge[e].w);
if (mxdis[v] + edge[e].w > maxx) {
minx = maxx;
maxx = mxdis[v] + edge[e].w;
} else if (mxdis[v] + edge[e].w > minx)
minx = mxdis[v] + edge[e].w;
}
dia = max(dia, minx + maxx);
}
int main() {
read(n);
for (int i = 1; i <= n; ++i) {
int u, v, w;
read(u), read(v), read(w);
addedge(u, v, w);
addedge(v, u, w);
}
getloop(1);
for (int i = 1; i <= lpcnt; ++i) {
lop[i + lpcnt] = lop[i];
dfs(lop[i].fi, 0);
}
for (int i = 2; i <= lpcnt << 1; ++i)
sum[i] = sum[i - 1] + lop[i - 1].se;
for (int i = 1; i <= lpcnt; ++i) {
set1.insert(make_pair(mxdis[lop[i].fi] + sum[i], i));
set2.insert(make_pair(mxdis[lop[i].fi] - sum[i], i));
}
ans = INF;
for (int i = 1; i <= lpcnt; ++i) {
LL diameter;
if (set1.begin()->se == set2.begin()->se) {
multiset <PLI, greater <PLI> >::iterator ptr = set2.begin();
++ptr;
diameter = set1.begin()->first + ptr->first;
ptr = set1.begin();
++ptr;
diameter = max(diameter, ptr->first + set2.begin()->first);
} else
diameter = set1.begin()->first + set2.begin()->first;
ans = min(ans, diameter);
set1.erase(make_pair(mxdis[lop[i].fi] + sum[i], i));
set2.erase(make_pair(mxdis[lop[i].fi] - sum[i], i));
set1.insert(make_pair(mxdis[lop[i + lpcnt].fi] + sum[i + lpcnt], i + lpcnt));
set2.insert(make_pair(mxdis[lop[i + lpcnt].fi] - sum[i + lpcnt], i + lpcnt));
}
printf("%lld\n", max(ans, dia));
return 0;
}
- TIPS
- 前面提到树的直径是不变的,所以最后的答案不应该超过每个环上的点对应的树的直径。
- 数组别忘了开两倍...
【CodeForces】835F Roads in the Kingdom的更多相关文章
- 【CodeForces】671 D. Roads in Yusland
[题目]D. Roads in Yusland [题意]给定n个点的树,m条从下往上的链,每条链代价ci,求最少代价使得链覆盖所有边.n,m<=3*10^5,ci<=10^9,time=4 ...
- Codeforces 835 F. Roads in the Kingdom
\(>Codeforces\space835 F. Roads in the Kingdom<\) 题目大意 : 给你一棵 \(n\) 个点构成的树基环树,你需要删掉一条环边,使其变成一颗 ...
- 【Codeforces】Round #491 (Div. 2) 总结
[Codeforces]Round #491 (Div. 2) 总结 这次尴尬了,D题fst,E没有做出来.... 不过还好,rating只掉了30,总体来说比较不稳,下次加油 A:If at fir ...
- 【Codeforces】Round #488 (Div. 2) 总结
[Codeforces]Round #488 (Div. 2) 总结 比较僵硬的一场,还是手速不够,但是作为正式成为竞赛生的第一场比赛还是比较圆满的,起码没有FST,A掉ABCD,总排82,怒涨rat ...
- 【题解】Paid Roads [SP3953] [Poj3411]
[题解]Paid Roads [SP3953] [Poj3411] 传送门:\(\text{Paid}\) \(\text{Roads}\) \(\text{[SP3953]}\) \(\text{[ ...
- 【网络流】One-Way Roads
[网络流]One-Way Roads 题目描述 In the country of Via, the cities are connected by roads that can be used in ...
- Codeforces 835F Roads in the Kingdom - 动态规划
题目传送门 传送点I 传送点II 传送点III 题目大意 给定一颗基环树,要求删去其中一条边,使得剩下的图形是一棵树,并且最长路的长度最短,求最长路的最短长度. 路径可以分为两部分:跨过环 和 在树内 ...
- Codeforces 835F Roads in the Kingdom (环套树 + DP)
题目链接 Roads in the Kingdom 题意 给出一个环套树的结构,现在要删去这个结构中的一条边,满足所有点依然连通. 删边之后的这个结构是一棵树,求所有删边情况中树的直径的最小值. 显 ...
- 【CodeForces】601 D. Acyclic Organic Compounds
[题目]D. Acyclic Organic Compounds [题意]给定一棵带点权树,每个点有一个字符,定义一个结点的字符串数为往下延伸能得到的不重复字符串数,求min(点权+字符串数),n&l ...
随机推荐
- jmeter远程调用
jmeter版本相同 JDK版本1.7以上 脚本文件在所有机器上的路径都一致 修改远程机器jmeter bin目录下的jmeter.properties文件配置:server_port=1001 多个 ...
- git注册到git管理远程仓库
注册: ① 注册github网站:地址:https://github.com/,其中sign up 是注册,sign in是登录 (如果是用QQ邮箱的话,如果觉得收不到邮箱,可能是在垃圾箱哦) ② 之 ...
- JDK13环境变量配置
第一步:下载JDK(开发工具包) JDK分为OracleJDK和OpenJDK下面简要说明 OracleJDK 部分代码闭源.商业收费 OpenJDK 开放源码.商业免费 两者大部分代码是共用的(除闭 ...
- Java面试之Java基础问题答案口述整理
Java面试之基础问题答案口述整理 面向对象的理解 面向对象思想就是在计算机程序设计过程中,把具体事物的属性特性和行为特征抽象出来,描述成计算机事件的设计思想.它区别于面向过程的思想,强调的是通过调用 ...
- 一个提高N倍系统新能的编程点,却总是被普通开发们遗忘
位运算这个概念并不陌生,大多数程序员在进入这个领域的时候或多或少都接触过位运算,估计当时都写过不少练习题的. 位运算本身不难,困难的是大家没有学会在系统设计时用上它,提高系统性能,增加你的不可替代性. ...
- 1500多套微信小程序带后端源码-史上最全的不同行业的源码集合
如何下载获取在最后面! 部分源码 部分源码 部分源码 部分截图 o2o行业 | - 盒马鲜生 | - 轻客洗衣 互联网行业 | - 云文档 | - 仿ofo共享单车 | - 仿美团外卖 | - 仿饿了 ...
- 记一次Java获取本地摄像头(基于OpenCV)
OpenCV官网下载地址(下载安装后,在安装目录可以找到动态链接库和OpenCv.jar) https://opencv.org/releases/ 安装完成后,这是我的安装目录 maven 依赖(这 ...
- python协程(yield、asyncio标准库、gevent第三方)、异步的实现
引言 同步:不同程序单元为了完成某个任务,在执行过程中需靠某种通信方式以协调一致,称这些程序单元是同步执行的. 例如购物系统中更新商品库存,需要用"行锁"作为通信信号,让不同的更新 ...
- 转载:关于Python3中venv虚拟环境
https://www.cnblogs.com/zhaof/p/7299025.html
- springboot maven项目运行常见报错 及ajax请求报错
如图所示 tomcat运行后直接停止,也不报错 原因:我的原因是controller路径配置重名或者service没有配置@Service 遇见这错找了好久问题,网上也搜不到,特此记录一下 问题2 a ...