[洛谷P3761] [TJOI2017]城市
洛谷题目链接:[TJOI2017]城市
题目描述
从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作。这个地区一共有ri座城市,《-1条高速公路,保证了任意两运城市之间都可以通过高速公路相互可达,但是通过一条高速公路需要收取一定的交通费用。小明对这个地区深入研究后,觉得这个地区的交通费用太贵。小明想彻底改造这个地区,但是由于上司给他的资源有限,因而小明现在只能对一条高速公路进行改造,改造的方式就是去掉一条高速公路,并且重新修建一条一样的高速公路(即交通费用一样),使得这个地区的两个城市之间的最大交通费用最小(即使得交通费用最大的两座城市之间的交通费用最小),并且保证修建完之后任意两座城市相互可达。如果你是小明,你怎么解决这个问题?
输入输出格式
输入格式:
输入数据的第一行为一个整数n,代表城市个数。
接下来的n - 1行分别代表了最初的n-1条公路情况。每一行都有三个整数u,v,d。u,v代表这条公路的两端城市标号,d代表这条公路的交通费用。
1 <= u,v <= n,1<= d <= 2000
输出格式:
输出数据仅有一行,一个整数,表示进行了最优的改造之后,该地区两城市 之间最大交通费用。
输入输出样例
输入样例#1:
5
1 2 1
2 3 2
3 4 3
4 5 4
输出样例#1:
7
说明
对于30%的数据,1<=n<500
对于100%的数据,1<=n<=5000
一句话题意: 给出一颗树,现在可以断开一条边并重新选择一个位置连接使得这张图仍然是一棵树.
题解: 因为在一棵树上断掉一条边之后,一定会成为两个连通块.那么再在这两个连通块中连一条边,两个连通块重新组成一棵树,那么这时树中的最长的距离就是新组成的直径.
那么新组成的直径该怎么计算呢?
显然我们可以分情况讨论:
- 断开一条边后形成的两个连通块中一条直径比较长,另一条直径比较短,将直径短的那颗树接到直径较长的树中后新树的直径仍然小于之前较长的直径.
- 两条直径差不多长,无论怎么接都会增加长度.此时我们需要它增加的长度尽量小,那么显然是要将两根直径的一半的位置接起来.此时直径可能不能恰好分成平均的两段,我们需要取折半后的较长段的最小值作为半径(想一下为什么).
那么这样就将所有的合并情况都讨论出来了,我们只需要枚举每一条边断开然后取合并后的最小值就可以了.
#include<bits/stdc++.h>
using namespace std;
const int N = 5000+5;
const int inf = 2147483647;
int n, ecnt = 1, last[N], ans = inf, f[N], fa[N], q[N], cnt, dist[N], pre[N], dep[N];
int len[2], L[2], R[2];
struct edge{
int from, nex, to, w;
}e[N*2];
void add(int x, int y, int z){
e[++ecnt].to = y, e[ecnt].w = z, e[ecnt].from = x, e[ecnt].nex = last[x], last[x] = ecnt;
}
void dfs(int x, int las, int deep, int k){
dep[x] = deep, fa[x] = las;
for(int to, i=last[x];i;i=e[i].nex){
to = e[i].to; if(to == las) continue;
dfs(to, x, deep+1, k);
if(len[k] < f[x]+f[to]+e[i].w) len[k] = f[x]+f[to]+e[i].w, L[k] = pre[x], R[k] = pre[to];
if(f[x] < f[to]+e[i].w) f[x] = f[to]+e[i].w, pre[x] = pre[to];
}
}
void get_dis(int x, int lca){
if(x == lca){ q[++cnt] = x; return; }
get_dis(fa[x], lca), q[++cnt] = x;
}
int get(int x, int y){
cnt = 0 ; int lca, a = x, b = y, mn = inf;
if(dep[a] < dep[b]) swap(a, b);
while(dep[a] > dep[b]) a = fa[a];
if(a == b) lca = a;
else { while(a != b) a = fa[a], b = fa[b]; lca = a; }
while(x != lca) q[++cnt] = x, x = fa[x]; get_dis(y, lca);
for(int i=2;i<=cnt;i++)
for(int j=last[q[i]];j;j=e[j].nex)
if(e[j].to == q[i-1]) dist[q[i]] = dist[q[i-1]]+e[j].w;
for(int i=1;i<=cnt;i++) mn = min(mn, max(dist[q[i]], dist[q[cnt]]-dist[q[i]]));
return mn;
}
void solve(int x, int y, int w){
memset(dist, 0, sizeof(dist)), L[0] = L[1] = R[0] = R[1] = 0;
memset(f, 0, sizeof(f)), len[0] = len[1] = 0;
for(int i=1;i<=n;i++) pre[i] = i;
dfs(x, y, 1, 0), dfs(y, x, 1, 1);
ans = min(ans, max(get(L[0], R[0])+get(L[1], R[1])+w, max(len[0], len[1])));
}
int main(){
ios::sync_with_stdio(false);
int x, y, z; cin >> n;
for(int i=1; i<n; i++) cin >> x >> y >> z, add(x, y, z), add(y, x, z);
for(int i=2; i<=ecnt; i+=2) solve(e[i].from, e[i].to, e[i].w);
cout << ans << endl;
return 0;
}
[洛谷P3761] [TJOI2017]城市的更多相关文章
- 换根DP+树的直径【洛谷P3761】 [TJOI2017]城市
P3761 [TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公 ...
- [洛谷P3763] [TJOI2017]DNA
洛谷题目链接:[TJOI2017]DNA 题目描述 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其 ...
- 【经典DP】洛谷 P2782 友好城市
嘤嘤嘤,昨天两个文化课老师在上奥赛时招呼我(亲切交流),今天又要写工作报告,没时间写题解,希望今天能补上 友好城市 题目://洛谷那粘来的题面竟然能把格式粘过来 题目描述 有一条横贯东西的大河,河有笔 ...
- 洛谷P3759 [TJOI2017]不勤劳的图书管理员 【树状数组套主席树】
题目链接 洛谷P3759 题解 树状数组套主席树板题 #include<algorithm> #include<iostream> #include<cstring> ...
- 洛谷P3763 [Tjoi2017]DNA 【后缀数组】
题目链接 洛谷P3763 题解 后缀数组裸题 在BZOJ被卡常到哭QAQ #include<algorithm> #include<iostream> #include< ...
- 洛谷P2782 友好城市 DP
やはり まだあしたということは嘘でしょう.ぜんぶ忘れた( ´・ヮ・`) 所以今天就贴一道水题吧 原题>>https://www.luogu.org/problem/show?pid=278 ...
- 洛谷P2782 友好城市
题目描述 有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市.北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同.没对友好城市都向政府申请在河上开辟一条直线航 ...
- 洛谷P3760 - [TJOI2017]异或和
Portal Description 给出一个\(n(n\leq10^5)\)的序列\(\{a_n\}(\Sigma a_i\leq10^6)\),求该数列所有连续和的异或和. Solution 线段 ...
- 洛谷P3759 - [TJOI2017]不勤劳的图书管理员
Portal Description 给出一个\(1..n(n\leq5\times10^4)\)的排列\(\{a_n\}\)和数列\(\{w_n\}(w_i\leq10^5)\),进行\(m(m\l ...
随机推荐
- Block的声明与定义语法
Block的声明 Block的声明与函数指针的声明类似 返回值类型(^变量名)(参数列表) Block的定义 ^返回值类型(参数列表) { 表达式 } 其中: 1 如果返回值类型是void,可以省略 ...
- C++ Mooc学习
# C++远征篇之起航 1.IDE搭建,现在大部分同学都使用devC,devC的debug调试功能特别好用,可以跟踪变量.省去了在中间插入一些输出语句来输出中间变量的麻烦. 2.using names ...
- java中 i = i++和 j = i++ 的区别
由于i++和i--的使用会导致值的改变,所以在处理后置的++和--的时候,java的编译器会重新为变量分配一块新的内存空间,用来存放原来的值, 而完成赋值运算之后,这块内存会被释放. (1)对于j = ...
- OSG学习:移动/缩放/旋转模型
移动和缩放以及旋转都是对矩阵进行操作,这些操作如果要叠加直接矩阵相乘就可以了. 下面的示例代码中,加入了四个bignathan,一个是默认加入在最中间,一个向上移2单位,一个是向下移2单位且缩放0.5 ...
- 【redis数据库学习】用JAVA连接redis数据库各种报错
最近项目中,需要用到redis数据库,然后使用Jedis让JAVA连接redis. 首先,安装redis数据库,参考的是:http://www.runoob.com/redis/redis-insta ...
- html中图片自适应浏览器和屏幕,宽度高度自适应
1.(宽度自适应):在网页代码的头部,加入一行viewport元标签. <meta name="viewport" content="width=device-wi ...
- 【Linux】- Ubuntu安装redis,并开启远程访问
Ubuntu16.04安装Redis 开启Redis远程访问的步骤: 1.注释掉redis配置文件中的,bind 127.0.0.1 sudo vi /etc/redis/redis.conf #注释 ...
- jconsole工具监控java运行情况
jconsole是jdk自带的工具.所以要先安装jdk 1.jconsole工具的路径: 通过which jconsole来查看 /usr/local/jdk1.7.0_79/bin/jconsol ...
- AppDomain.CurrentDomain.AssemblyResolve
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 参 ...
- Linux和Windows文件路径
linux系统下的文件夹路径和window下的不一样,windows下就需要写成“\\photos"因为java会把第一个"\"当成转义字符给“吃了”.但在linux下就 ...