Codeforces 835 F Roads in the Kingdom(树形dp)
F. Roads in the Kingdom(树形dp)
题意:
给一张n个点n条边的无向带权图
定义不便利度为所有点对最短距离中的最大值
求出删一条边之后,保证图还连通时不便利度的最小值
$n <= 2e5 $
\(w_i <= 1e9\)
思路:树形dp
这个图是一个环上挂着很多颗树,首先把这个环处理出来,
删边只能在环上进行,所以可以先求出以环上每个点为根的树的直径和最大深度dep,
答案来源分为二种
- 树内部两点最远距离 -> 直径 (树形dp 或者 两次bfs)
- 两棵树深度最大的两点配对
假设环长度为\(k\),把环变成一个序列\(a_1,a_2,...,a_k\) 令\(a_0 = a_k\)
选择\(a_0\)做起点,用\(s_i\)表示第\(i\)个点到起点的距离
考虑每次断开的边为\(e(a_{i-1},a_i)\),那么答案分为三种情况
- 序列\(1\)到\(i-1\)中选两个点配对取最大值
- 序列\(i\)到\(k\)中选两个点配对取最大值
- 前后各取一个点配对取最大值
计算第一种情况
假设取的两个点为\(1<=x<y<=i-1\),
则距离\(d = dep[x] + dep[y] + dis[x][y] = dep[x] - s[x] + dep[y] + s[y]\)
这样我们只需要顺序枚举维护\(dep[x] - s[x]\)的最大值即可
同理,第二种情况只需要逆序枚举维护\(dep[x] + s[x]\)的最大值即可
考虑第三种情况 假设取的点为\(1 <= x <= i - 1 , i <= y <= k\)
则距离\(d = dep[x] + dep[y] + dis[x][y] = dep[x] + dep[y] + s[k] - (s[y] - s[x])\)
$d = (dep[x] + s[k] + s[x]) + (dep[y] - s[y]) $
同理,顺序可算出第一部分最大值,逆序可以算出第二部分最大值
最后在删边后三种情况的最大值里取最小值再和树内部直径比较即可
#include<bits/stdc++.h>
#define LL long long
#define P pair<int,int>
#define ls(i) seg[i].lc
#define rs(i) seg[i].rc
using namespace std;
const int N = 2e5 + 10;
const LL inf = 1e18;
int read(){
int x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
return x;
}
vector<P>G[N];
int n,k;
int a[N],pa[N],e[N];
LL s[N],dep[N],ans;
void dfs(int u,int fa){
pa[u] = fa;
for(auto v:G[u]){
if(v.first == fa) continue;
if(pa[v.first] == 0) {
e[v.first] = v.second;
dfs(v.first,u);
}
else if(!k){
int x = u;
a[0] = v.first,s[1] = v.second;
while(x != v.first) {
a[++k] = x,s[k+1] = s[k] + e[x],x = pa[x];
}
a[++k] = v.first;
}
}
}
void dp(int u){
pa[u] = 0;
for(auto v:G[u]){
if(pa[v.first] != 0){
dp(v.first);
ans = max(ans,dep[v.first] + v.second + dep[u]);
dep[u] = max(dep[u], dep[v.first] + v.second);
}
}
}
LL sL[N],sR[N],L[N],R[N];///把环变成序列,断开的边左边配对,右边配对,左右配对的最大值
int main(){
int u,v,w;
n = read();
for(int i = 1;i <= n;i++){
u = read(),v = read(),w = read();
G[u].push_back(P(v,w));
G[v].push_back(P(u,w));
}
k = 0;
ans = 0;
dfs(1,-1);
for(int i = 1;i <= k;i++) pa[a[i]] = 0;
for(int i = 1;i <= k;i++) dp(a[i]);
LL mx = -inf;
L[0] = sL[0] = -inf;
for(int i = 1;i <= k;i++){
sL[i] = max(sL[i-1],dep[a[i]] + s[i] + mx);
L[i] = max(L[i-1],dep[a[i]] + s[k] + s[i]);
mx = max(mx, dep[a[i]] - s[i]);
}
sR[k+1] = R[k+1] = mx = -inf;
for(int i = k;i >= 1;i--){
sR[i] = max(sR[i+1],dep[a[i]] - s[i] + mx);
R[i] = max(R[i+1],dep[a[i]] - s[i]);
mx = max(mx, dep[a[i]] + s[i]);
}
LL tmp = inf;
for(int i = 1;i <= k;i++) tmp = min(tmp,max(L[i-1]+R[i],max(sL[i-1],sR[i])));
cout<<max(ans,tmp)<<endl;
return 0;
}
Codeforces 835 F Roads in the Kingdom(树形dp)的更多相关文章
- Codeforces 835 F. Roads in the Kingdom
\(>Codeforces\space835 F. Roads in the Kingdom<\) 题目大意 : 给你一棵 \(n\) 个点构成的树基环树,你需要删掉一条环边,使其变成一颗 ...
- codeforces 427 div.2 F. Roads in the Kingdom
F. Roads in the Kingdom time limit per test 2 seconds memory limit per test 256 megabytes input stan ...
- Codeforces 671D. Roads in Yusland(树形DP+线段树)
调了半天居然还能是线段树写错了,药丸 这题大概是类似一个树形DP的东西.设$dp[i]$为修完i这棵子树的最小代价,假设当前点为$x$,但是转移的时候我们不知道子节点到底有没有一条越过$x$的路.如果 ...
- Codeforces Round #527 F - Tree with Maximum Cost /// 树形DP
题目大意: 给定一棵树 每个点都有点权 每条边的长度都为1 树上一点到另一点的距离为最短路经过的边的长度总和 树上一点到另一点的花费为距离乘另一点的点权 选定一点出发 使得其他点到该点的花费总和是最大 ...
- Codeforces 1097G Vladislav and a Great Legend [树形DP,斯特林数]
洛谷 Codeforces 这题真是妙的很. 通过看题解,终于知道了\(\sum_n f(n)^k\)这种东西怎么算. update:经过思考,我对这题有了更深的理解,现将更新内容放在原题解下方. ...
- Codeforces 1606F - Tree Queries(虚树+树形 dp)
Codeforces 题面传送门 & 洛谷题面传送门 显然我们选择删除的点连同 \(u\) 会形成一个连通块,否则我们如果选择不删除不与 \(u\) 在同一连通块中的点,答案一定更优. 注意到 ...
- Codeforces 791D Bear and Tree Jump(树形DP)
题目链接 Bear and Tree Jumps 考虑树形DP.$c(i, j)$表示$i$最少加上多少后能被$j$整除. 在这里我们要算出所有$c(i, k)$的和. 其中$i$代表每个点对的距离, ...
- codeforces 816 E. Karen and Supermarket(树形dp)
题目链接:http://codeforces.com/contest/816/problem/E 题意:有n件商品,每件有价格ci,优惠券di,对于i>=2,使用di的条件为:xi的优惠券需要被 ...
- codeforces 161 D. Distance in Tree(树形dp)
题目链接:http://codeforces.com/problemset/problem/161/D 题意:给出一个树,问树上点到点的距离为k的一共有几个. 一道简单的树形dp,算是一个基础题. 设 ...
随机推荐
- 【读书笔记】你不知道的JavaScript(上卷)--作用域是什么
第一章 作用域 1.理解作用域 几个名词的介绍 引擎:从头到尾负责整个JavaScript程序的编译及执行过程 编译器:负责语法分析及代码生成器等脏活累活 作用域:负责收集并维护由所有声明的标识符(变 ...
- 【操作系统作业-lab4】 linux 多线程编程和调度器
linux多线程编程 参考:https://blog.csdn.net/weibo1230123/article/details/81410241 https://blog.csdn.net/skyr ...
- 设置vim tab为4个空格
Vim 编辑器默认tab为8个空格,但对于pythoner来说,必须要调整到4个空格. 方法如下: 在~/.vimrc文件中加入下面设置: set ts=4 #设置tabstop为4个空格 set e ...
- JAVAOOP异常
排序: Try-catch-finally:try正常执行,如果有异常执行catch后执行finally,如果没有直接执行finally 执行顺序:try-catch:try中的语句正常执行,如果遇到 ...
- <Docker学习>4. docker容器的使用
简单的说, 容器是独立运行的一个或一组应用, 以及它们的运行态环境. 对应的, 虚拟机可以理解为模拟运行的一整套操作系统( 提供了运行态环境和其他系统环境) 和跑在上面的应用.容器的运行是基于镜像的. ...
- 图解HTTP总结(5)——与HTTP协作的Web服务器
一台 Web 服务器可搭建多个独立域名的 Web 网站, 也可作为通信路径上的中转服务器提升传输效率. 用单台虚拟主机实现多个域名 HTTP/1.1 规范允许一台 HTTP 服务器搭建多个 Web 站 ...
- zookeeper集群(二)
经过前一篇文章<zookeeper伪集群一>的阅读,相信大家对zookeeper集群已经有一定的了解了,接下来我们再谈谈zookeeper真集群.其实真集群和伪集群还是有很多相似的部分的, ...
- PyQuery网页解析库
from pyquery import PyQuery as pq 字符串初始化: doc = pq(html) URL初始化:doc = pq(url = "···") 文件初始 ...
- C语言数组篇(二)指针数组和数组指针
数组指针 和 指针数组 这两个名词可以说是经常搞混了 数组指针--> 数组的指针 就是前面讲的 指向数组a的指针p; 指针数组--&g ...
- TouTiao开源项目 分析笔记8 图解分析数据加载方式
1.整体构架 1.1.以一个段子页面为例,列出用到的主要的类,以图片的方式展示. 1.2.基础类 这里最基础的接口有: IBaseView<T>==>定义了5个方法. 然后最基础 ...