CF835F Roads in the Kingdom/UOJ126 NOI2013 快餐店 树的直径
题目要求基环树删掉环上的一条边得到的树的直径的最小值。
如果直接考虑删哪条边最优似乎不太可做,于是考虑另一种想法:枚举删掉的边并快速地求出当前的直径。
对于环上的点,先把它的子树计算完毕,然后将最深的那条链接在这个点上,即记录每个点子树的最深深度,记为\(dep_i\)。然后枚举环上的节点\(x\),设\(dis_y\)表示从\(x\)开始顺时针到达\(y\)需要走多远(相当于将\(x\)和其逆时针遇到的第一个点之间的边删掉),那么当前的直径就是\(\max\limits_{dis_i < dis_j} {dep_i - dis_i + dep_j + dis_j}\),拿两个\(set\)把\(dep_i - dis_i\)、\(dep_i + dis_i\)记录起来取\(max\)。因为\(dis_i < dis_j \rightarrow dep_i - dis_i + dep_j + dis_j > dep_i + dis_i + dep_j - dis_j\),所以不会发生错位的情况。如果\(dep_i - dis_i\)和\(dep_i + dis_i\)在同一个\(i\)处取到最大值,就两个中一个选最大值、一个选次大值,两种方案取\(max\)
然后考虑换边,将枚举的点从\(x\)移到\(x\)顺时针方向的第一个点\(z\)。会发生改变的是\(dis\),设其改变到\(dis'\)。又设环长为\(cir\),那么\(dis'_x = cir - w(x,z)\),\(\forall y \neq x , dis'_y = dis_y - w(x,z)\)。所以直接修改\(dis_x\)为\(cir\)即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<set>
//This code is written by Itst
using namespace std;
const int MAXN = 2e5 + 9;
struct Edge{
int end , upEd , w;
}Ed[MAXN << 1];
int head[MAXN] , N , cntEd = 1;
bool vis[MAXN];
inline void addEd(int a , int b , int c){
Ed[++cntEd] = (Edge){b , head[a] , c};
head[a] = cntEd;
}
int find(int x , int uped){
vis[x] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(i != (uped ^ 1))
if(!vis[Ed[i].end]){
int t = find(Ed[i].end , i);
if(t) return t == x ? 0 : t;
}
else
return Ed[i].end;
return vis[x] = 0;
}
long long sum , dp[MAXN] , len[MAXN] , cir = 1e18 , ans;
vector < int > incir;
bool pos[MAXN];
void dfs(int x , int p){
if(vis[x]) incir.push_back(x);
pos[x] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end] && Ed[i].end != p){
dfs(Ed[i].end , x);
ans = max(ans , dp[x] + dp[Ed[i].end] + Ed[i].w);
dp[x] = max(dp[x] , dp[Ed[i].end] + Ed[i].w);
}
else
if(vis[Ed[i].end] && !pos[Ed[i].end]){
len[Ed[i].end] = len[x] + Ed[i].w;
dfs(Ed[i].end , x);
}
}
#define PLI pair < long long , int >
#define st first
#define nd second
set < PLI > s1 , s2;
set < PLI > :: iterator it1 , it2;
void solve(){
for(int i = 0 ; i < incir.size() ; ++i){
s1.insert(PLI(dp[incir[i]] + len[incir[i]] , i));
s2.insert(PLI(dp[incir[i]] - len[incir[i]] , i));
}
for(int i = 0 ; i < incir.size() ; ++i){
it1 = --s1.end(); it2 = --s2.end();
if(it1->nd == it2->nd){
long long t = (--it1)->st + it2->st;
cir = min(cir , max(t , (++it1)->st + (--it2)->st));
}
else
cir = min(cir , it1->st + it2->st);
s1.erase(s1.find(PLI(dp[incir[i]] + len[incir[i]] , i)));
s2.erase(s2.find(PLI(dp[incir[i]] - len[incir[i]] , i)));
s1.insert(PLI(dp[incir[i]] + len[incir[i]] + sum , i));
s2.insert(PLI(dp[incir[i]] - len[incir[i]] - sum , i));
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
cin >> N;
for(int i = 1 ; i <= N ; ++i){
int a , b , c;
cin >> a >> b >> c;
addEd(a , b , c); addEd(b , a , c);
}
find(1 , 0);
for(int i = 1 ; i <= N ; ++i)
if(vis[i]){
dfs(i , 0);
break;
}
for(int i = 0 ; i < incir.size() ; ++i)
for(int j = head[incir[i]] ; j ; j = Ed[j].upEd)
if(Ed[j].end == incir[(i + 1) % incir.size()]){
sum += Ed[j].w;
if(incir.size() > 2)
break;
}
if(incir.size() == 2) sum >>= 1;
solve();
cout << max(ans , cir);
return 0;
}
CF835F Roads in the Kingdom/UOJ126 NOI2013 快餐店 树的直径的更多相关文章
- [NOI2013]快餐店 / CF835F Roads in the Kingdom (基环树)
题意 一颗基环树,选一对点使得这两个点的最短距离最大. 题解 相当于找基环树的直径,但是这个直径不是最长链,是基环树上的最短距离. 然后不会做. 然后看了ljh_2000的博客. 然后会了. 这道题最 ...
- BZOJ3242/UOJ126 [Noi2013]快餐店
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- CF835F Roads in the Kingdom
话说这是去年大爷的一道NOIP模拟赛题,对着大爷的代码看了一堂课的我终于把这题写掉了. 本题要求在基环树给定的环上删去一条边使剩下的树的直径最小,输出这个最小直径. 那么基环树可以画成这样子的: 有一 ...
- bzoj 3242: [Noi2013]快餐店 章鱼图
3242: [Noi2013]快餐店 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 266 Solved: 140[Submit][Status] ...
- Codeforces 835 F. Roads in the Kingdom
\(>Codeforces\space835 F. Roads in the Kingdom<\) 题目大意 : 给你一棵 \(n\) 个点构成的树基环树,你需要删掉一条环边,使其变成一颗 ...
- Codeforces 835 F Roads in the Kingdom(树形dp)
F. Roads in the Kingdom(树形dp) 题意: 给一张n个点n条边的无向带权图 定义不便利度为所有点对最短距离中的最大值 求出删一条边之后,保证图还连通时不便利度的最小值 $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 835F Roads in the Kingdom (环套树 + DP)
题目链接 Roads in the Kingdom 题意 给出一个环套树的结构,现在要删去这个结构中的一条边,满足所有点依然连通. 删边之后的这个结构是一棵树,求所有删边情况中树的直径的最小值. 显 ...
- P1399 [NOI2013] 快餐店 方法记录
原题题面P1399 [NOI2013] 快餐店 题目描述 小 T 打算在城市 C 开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小 T 希望快餐店的地址选在离最 ...
随机推荐
- 【代码笔记】Web-ionic-创建APP的架构
一,创建app的时候,index.html的主要架构. <!DOCTYPE html> <html> <head> <meta charset="u ...
- 【工具相关】Web-HTML特殊字符对照表
特殊符号 命名实体 十进制编码 特殊符号 命名实体 十进制编码 特殊符号 命名实体 十进制编码 Α Α Α Β Β Β Γ Γ Γ Δ Δ Δ Ε Ε Ε Ζ Ζ Ζ Η Η Η Θ Θ Θ Ι Ι ...
- 前端开发面试题-CSS(转载)
本文由 本文的原作者markyun 收集总结. 介绍一下标准的CSS的盒子模型?低版本IE的盒子模型有什么不同的? (1)有两种, IE 盒子模型.W3C 盒子模型: (2)盒模型: 内容(conte ...
- AppBoxPro(权限管理框架--FineUIPro基础版+工厂模式+ADO.NET+存储过程)
FineUIPro基础版火爆来袭,特献上ADO.NET纯SQL方式AppBoxPro,希望大家能够喜欢! 下载源码请到[知识星球] https://t.zsxq.com/3rrNFyv
- mysql从入门到放弃-入门知识介绍
数据库在互联网网站的重要性 简单地说,数据库就是一个存放数据的仓库,这个仓库是按照一定的数据结构来组织和存储的,我们可以通过数据库提供的多种方法来管理数据库里的数据.由于数据库不易扩展,所以,在一个互 ...
- Expo大作战(三十五)--expo sdk api之Location!
简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...
- 14.python与数据库之mysql:pymysql、sqlalchemy
相关内容: 使用pymysql直接操作mysql 创建表 查看表 修改表 删除表 插入数据 查看数据 修改数据 删除数据 使用sqlmary操作mysql 创建表 查看表 修改表 删除表 插入数据 查 ...
- React 表单与事件
一个简单是实例 在实例中我们设置了输入框 input 值value = {this.state.data}.在输入框值发生变化时我们可以更新 state.我们可以使用 onChange 事件来监听 i ...
- 11-OpenLDAP主从同步
OpenLDAP主从同步 阅读视图 部署环境 OpenLDAP服务器初始化 配置主服务器同步策略 配置从服务器 OpenLDAP主从同步验证 故障诊断 1. 部署环境 本文以两台服务器为蓝本演示其同步 ...
- C#与Java AES 加密解密
参考文档:https://www.cnblogs.com/xbzhu/p/7064642.html 前几天对接Java接口,需要C#加密参数,Java解密.奈何网上找了一堆大同小异的加解密方法都跟Ja ...