洛谷题目链接:[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


一句话题意: 给出一颗树,现在可以断开一条边并重新选择一个位置连接使得这张图仍然是一棵树.


题解: 因为在一棵树上断掉一条边之后,一定会成为两个连通块.那么再在这两个连通块中连一条边,两个连通块重新组成一棵树,那么这时树中的最长的距离就是新组成的直径.

那么新组成的直径该怎么计算呢?

显然我们可以分情况讨论:

  1. 断开一条边后形成的两个连通块中一条直径比较长,另一条直径比较短,将直径短的那颗树接到直径较长的树中后新树的直径仍然小于之前较长的直径.
  2. 两条直径差不多长,无论怎么接都会增加长度.此时我们需要它增加的长度尽量小,那么显然是要将两根直径的一半的位置接起来.此时直径可能不能恰好分成平均的两段,我们需要取折半后的较长段的最小值作为半径(想一下为什么).

那么这样就将所有的合并情况都讨论出来了,我们只需要枚举每一条边断开然后取合并后的最小值就可以了.

#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]城市的更多相关文章

  1. 换根DP+树的直径【洛谷P3761】 [TJOI2017]城市

    P3761 [TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公 ...

  2. [洛谷P3763] [TJOI2017]DNA

    洛谷题目链接:[TJOI2017]DNA 题目描述 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其 ...

  3. 【经典DP】洛谷 P2782 友好城市

    嘤嘤嘤,昨天两个文化课老师在上奥赛时招呼我(亲切交流),今天又要写工作报告,没时间写题解,希望今天能补上 友好城市 题目://洛谷那粘来的题面竟然能把格式粘过来 题目描述 有一条横贯东西的大河,河有笔 ...

  4. 洛谷P3759 [TJOI2017]不勤劳的图书管理员 【树状数组套主席树】

    题目链接 洛谷P3759 题解 树状数组套主席树板题 #include<algorithm> #include<iostream> #include<cstring> ...

  5. 洛谷P3763 [Tjoi2017]DNA 【后缀数组】

    题目链接 洛谷P3763 题解 后缀数组裸题 在BZOJ被卡常到哭QAQ #include<algorithm> #include<iostream> #include< ...

  6. 洛谷P2782 友好城市 DP

    やはり まだあしたということは嘘でしょう.ぜんぶ忘れた( ´・ヮ・`) 所以今天就贴一道水题吧 原题>>https://www.luogu.org/problem/show?pid=278 ...

  7. 洛谷P2782 友好城市

    题目描述 有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市.北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同.没对友好城市都向政府申请在河上开辟一条直线航 ...

  8. 洛谷P3760 - [TJOI2017]异或和

    Portal Description 给出一个\(n(n\leq10^5)\)的序列\(\{a_n\}(\Sigma a_i\leq10^6)\),求该数列所有连续和的异或和. Solution 线段 ...

  9. 洛谷P3759 - [TJOI2017]不勤劳的图书管理员

    Portal Description 给出一个\(1..n(n\leq5\times10^4)\)的排列\(\{a_n\}\)和数列\(\{w_n\}(w_i\leq10^5)\),进行\(m(m\l ...

随机推荐

  1. 【转】使用CNPM搭建私有NPM

    最近的Node项目中因为数据模型等问题,需要有一个对各个模块进行统一的管理,如果把私有的模型publish到公共的npm不太合适,所以决定使用cnpm搭建一个私有的npm,同时也可以对项目常用的npm ...

  2. 2. socket结构体——表示socket地址

    一.两种通用socket结构体 1. sockaddr struct sockaddr { sa_family_t sa_family; // 地址族 char sa_data[14]; // 存放s ...

  3. Thunder团队第五周 - Scrum会议2

    Scrum会议2 小组名称:Thunder 项目名称:i阅app Scrum Master:胡佑蓉 工作照片: 参会成员: 王航:http://www.cnblogs.com/wangh013/ 李传 ...

  4. Android - 按钮组件详解

    总结了Android中常用的按钮用法 示例源码下载地址 : -- CSDN :  http://download.csdn.net/detail/han1202012/6852091 -- GitHu ...

  5. 深入理解Java对象序列化(转载)

    原文地址:http://developer.51cto.com/art/201202/317181.htm 1. 什么是Java对象序列化 Java平台允许我们在内存中创建可复用的Java对象,但一般 ...

  6. LintCode-379.将数组重新排序以构造最小值

    将数组重新排序以构造最小值 给定一个整数数组,请将其重新排序,以构造最小值. 注意事项 The result may be very large, so you need to return a st ...

  7. <Effective C++>读书摘要--Ctors、Dtors and Assignment Operators<二>

    <Item 9> Never call virtual functions during construction or destruction 1.you shouldn't call ...

  8. JavaScript:理解事件、事件处理函数、钩子函数、回调函数

    详情请点击 http://www.jianshu.com/p/a0c580ed3432

  9. centos7 下pycharm无法输入中文问题解决方案

    作者使用的pycharm是2017.2 在pycharm.sh脚本的如下行(大约在201行): # -------------------------------------------------- ...

  10. BZOJ 1786 配对(DP)

    如果我们直接令dp[i][j]为前i个位置第i个位置填j所产生的逆序对的最少数.这样是不满足无后效性的. 但是如果发现对于两个-1,如果前面的-1填的数要大于后面的-1填的数.容易证明把他们两交换结果 ...