http://codeforces.com/gym/100676/attachments

题目大意:

有n个城市,有m条路,每条路都有边长,如果某几个城市的路能组成一个环,那么在环中的这些城市就有传送门,能够瞬间抵达对方的城市(即距离为0),否则,就要走这条路,并且经过的路程为这条路的长度。

问,找一个城市作为这些城市的首都

要求:除了首都城市外,其他城市到首都的最大距离最短。

思路:

边双连通缩点以后就是一棵树,找树上的直径,首都一定是直径上的点。(orz,自己明明注意到了一定是直径上面的点,在之前的好多次的wa中却忘了是要找直径上的点了)

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
/*
思路:
双连通缩点,然后随便找一个点树dp,
树dp,距离最短的肯定就是直径上的某一个点
*/
const int maxn = 1e5 + ;
const int maxm = 2e5 + ;
const LL inf = 1e17;
vector<pair<int, LL> > G[maxn];
int n, m;
/*****************/
int dfstime, bcccnt;
bool iscut[maxn];
int bccnu[maxn], pre[maxn];
stack<int> s;
vector<int> bcc[maxn]; int dfs(int u, int fa){
int lowu = pre[u] = ++dfstime;
int len = G[u].size();
int child = ;
s.push(u);
for (int i = ; i < len; i++){
int v = G[u][i].fi;
if (pre[v] == -){
child++;
int lowv = dfs(v, u);
lowu = min(lowv, lowu);
if (lowv > pre[u]){
iscut[u] = true;
}
}
else if (pre[v] < pre[u] && v != fa){
lowu = min(lowu, pre[v]);
}
}
if (lowu == pre[u]){
bcccnt++;
while (true){///边双连通分量是不存在重点的
int v = s.top(); s.pop();
bccnu[v] = bcccnt;
bcc[bcccnt].pb(v);
if (v == u) break;
}
}
if (fa == - && child == ) iscut[u] = false;
return lowu;
} void get_connect(){
dfstime = bcccnt = ;
memset(iscut, false, sizeof(iscut));
memset(bccnu, , sizeof(bccnu));
memset(pre, -, sizeof(pre));
dfs(, -);
} vector<pair<int, LL> > new_edge[maxn];
void rebuild(){
///O(n + m)
for (int i = ; i <= bcccnt; i++){
for (int j = ; j < bcc[i].size(); j++){
int u = bcc[i][j];
for (int k = ; k < G[u].size(); k++){
int v = G[u][k].fi;
LL val = G[u][k].se;
if (bccnu[u] != bccnu[v]){
new_edge[bccnu[u]].push_back(mk(bccnu[v], val));
}
}
}
}
/* printf("bcccnt = %d\n", bcccnt); cout << "new_edge.output" << endl;
for (int i = 1; i <= bcccnt; i++){
for (int j = 0; j < new_edge[i].size(); j++){
printf("u = %d v = %d val = %d\n", i, new_edge[i][j].fi, new_edge[i][j].se);
}
cout << endl;
}
*/
} int p; LL maxval;
LL can[maxn];
void dfs1(int u, int fa, LL sum){
if (sum > maxval){
maxval = sum, p = u;
}
for (int i = ; i < new_edge[u].size(); i++){
int v = new_edge[u][i].fi;
LL tmp = new_edge[u][i].se;
if (v == fa) continue;
dfs1(v, u, sum + tmp);
}
} LL d1[maxn], d2[maxn];
///d1从最底下到目前节点的距离
///d2表示从根到目前节点的距离
void dfs2(int u, int fa, LL sum){
d2[u] = sum;
for (int i = ; i < new_edge[u].size(); i++){
int v = new_edge[u][i].fi;
LL val = new_edge[u][i].se;
if (v == fa) continue;
dfs2(v, u, sum + val);
d1[u] = max(d1[u], d1[v] + val);
}
} LL mini;
vector<int> ansp;
void dfs3(int u, int fa){
for (int i = ; i < new_edge[u].size(); i++){
int v = new_edge[u][i].fi;
LL val = new_edge[u][i].se;
if (v == fa) continue;
if (d1[u] - val == d1[v]){
dfs3(v, u);
LL tmp = max(d1[u], d2[u]);
if (mini > tmp){
ansp.clear(); mini = tmp; ansp.pb(u);
}
else if (mini == tmp){
ansp.pb(u);
}
}
}
} int main(){
int t; cin >> t;
while (t--){
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++){
G[i].clear(); bcc[i].clear();
new_edge[i].clear();
}
for (int i = ; i <= m; i++){
int u, v; LL val; scanf("%d%d%lld", &u, &v, &val);
G[u].pb(mk(v, val)); G[v].pb(mk(u, val));
}
get_connect();
rebuild();
p = , maxval = ;
dfs1(, -, ); memset(d1, , sizeof(d1));
memset(d2, , sizeof(d2));
ansp.clear();
dfs2(p, -, 0LL); mini = inf;
dfs3(p, -); int ans = n + ;
for (int i = ; i < ansp.size(); i++){
int u = ansp[i];
for (int j = ; j < bcc[u].size(); j++){
ans = min(ans, bcc[u][j]);
}
}
if (ans == n + ) {ans = , mini = ;}
printf("%d %lld\n", ans, mini);
}
return ;
}

边双连通缩点+树dp 2015 ACM Arabella Collegiate Programming Contest的Gym - 100676H的更多相关文章

  1. Codeforces Gym 2015 ACM Arabella Collegiate Programming Contest(二月十日训练赛)

    A(By talker): 题意分析:以a(int) op b(int)形式给出两个整数和操作符, 求两个整数是否存在操作符所给定的关系 ,有则输出true,无则输出false: 思路:由于无时间复杂 ...

  2. 2015 ACM Arabella Collegiate Programming Contest

    题目链接:https://vjudge.net/contest/154238#overview. ABCDE都是水题. F题,一开始分类讨论,结果似乎写挫了,WA了一发.果断换并查集上,A了. G题, ...

  3. gym100676 [小熊骑士限定]2015 ACM Arabella Collegiate Programming Contest

    Kuma Rider久违的第二场训练,这场很水,又在vj的榜单上看到第一场的大哥了,2小时ak,大哥牛啤! A.水 #include<cstdio> #include<iostrea ...

  4. 18春季训练01-3/11 2015 ACM Amman Collegiate Programming Contest

    Solved A Gym 100712A Who Is The Winner Solved B Gym 100712B Rock-Paper-Scissors Solved C Gym 100712C ...

  5. ACM Arabella Collegiate Programming Contest 2015 H. Capital City 边连通分量

    题目链接:http://codeforces.com/gym/100676/attachments 题意: 有 n 个点,m 条边,图中,边强连通分量之间可以直达,即距离为 0 ,找一个点当做首都,其 ...

  6. 2015 ACM Amman Collegiate Programming Contest 题解

    [题目链接] A - Who Is The Winner 模拟. #include <bits/stdc++.h> using namespace std; int T; int n; s ...

  7. 2015 ACM Syrian Collegiate Programming Contest

    A. My Friend of Misery 计算出答案的上下界即可. 时间复杂度$O(n)$. #include<bits/stdc++.h> using namespace std; ...

  8. ACM Arabella Collegiate Programming Contest 2015 F. Palindrome 并查集

    题目链接:http://codeforces.com/gym/100676/attachments 题意: 给一个字符串,有一些约束条件,两个位置要相同,有一些是问号,求最后有多少种方案回文? 分析: ...

  9. ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest (2017)- K. Poor Ramzi -dp+记忆化搜索

    ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest (2017)- K. ...

随机推荐

  1. Java 学习笔记 ------第三章 基础语法

    本章学习目标: 认识类型与变量 学习运算符的基本使用 了解类型转换细节 运用基本流程语法 一.类型(基本类型) 所谓基本类型,就是在使用时,得考虑一下数据用多少内存长度存比较经济,利用程序语法告诉JV ...

  2. C++:this指针的简单理解

    一.什么是this指针 要想理解什么是this指针,首先必须理解在C++中是如何为类的对象分配内存空间的. #include<iostream> using namespace std; ...

  3. lintcode-464-整数排序 II

    464-整数排序 II 给一组整数,按照升序排序.使用归并排序,快速排序,堆排序或者任何其他 O(n log n) 的排序算法. 样例 给出 [3, 2, 1, 4, 5], 排序后的结果为 [1, ...

  4. Lucene 高级搜索

    自定义评分 public class MyScoreQuery { public void searchByScoreQuery(){ try { IndexSearcher searcher=new ...

  5. 新手必备!11个强大的 Visual Studio 调试技巧

    简介 调试是软件开发周期中很重要的一部分.它具有挑战性,同时也很让人疑惑和烦恼.总的来说,对于稍大一点的程序,调试是不可避免的.最近几年,调试工具的发展让很多调试任务变的越来越简单和省时. 这篇文章总 ...

  6. 对mysql联合索引中的字段进行合理排序

    在MySQL的where条件中,有时会用到很多的条件,通常为了加快速度会把这些字段放到联合索引中,可以更快的提高搜索速度: 但是对联合索引中字段顺序的合理排序,便更能提高速度 例子:select * ...

  7. windows操作系统下载tomcat,并与eclipse进行整合

    进入Tomcat官网之后,在左边我们看到,Tomcat的有6,7,8这三个最流行的版本,我们可以点击进去下载想要的版本. 进入里面之后,可以看见有64位的和32位的,就看自己的电脑是多少位的了,如果电 ...

  8. Java ISO 8601时间格式转换

    common-lang包: String pattern = "YYYY-MM-dd'T'HH:mm:ssZZ"; System.out.println(DateFormatUti ...

  9. centOS 中安装 Redis

    之前安装过了 jdk,mysql,tomcat,这次安装 Redis,最开始是将 redis 安装在 windows 下 run 的,这时安装在 Linux 里面试试. 1 . 首先得安装 c环境,用 ...

  10. [LeetCode] Search in Rotated Array

    Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...