边双连通缩点+树dp 2015 ACM Arabella Collegiate Programming Contest的Gym - 100676H
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的更多相关文章
- Codeforces Gym 2015 ACM Arabella Collegiate Programming Contest(二月十日训练赛)
A(By talker): 题意分析:以a(int) op b(int)形式给出两个整数和操作符, 求两个整数是否存在操作符所给定的关系 ,有则输出true,无则输出false: 思路:由于无时间复杂 ...
- 2015 ACM Arabella Collegiate Programming Contest
题目链接:https://vjudge.net/contest/154238#overview. ABCDE都是水题. F题,一开始分类讨论,结果似乎写挫了,WA了一发.果断换并查集上,A了. G题, ...
- gym100676 [小熊骑士限定]2015 ACM Arabella Collegiate Programming Contest
Kuma Rider久违的第二场训练,这场很水,又在vj的榜单上看到第一场的大哥了,2小时ak,大哥牛啤! A.水 #include<cstdio> #include<iostrea ...
- 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 ...
- ACM Arabella Collegiate Programming Contest 2015 H. Capital City 边连通分量
题目链接:http://codeforces.com/gym/100676/attachments 题意: 有 n 个点,m 条边,图中,边强连通分量之间可以直达,即距离为 0 ,找一个点当做首都,其 ...
- 2015 ACM Amman Collegiate Programming Contest 题解
[题目链接] A - Who Is The Winner 模拟. #include <bits/stdc++.h> using namespace std; int T; int n; s ...
- 2015 ACM Syrian Collegiate Programming Contest
A. My Friend of Misery 计算出答案的上下界即可. 时间复杂度$O(n)$. #include<bits/stdc++.h> using namespace std; ...
- ACM Arabella Collegiate Programming Contest 2015 F. Palindrome 并查集
题目链接:http://codeforces.com/gym/100676/attachments 题意: 给一个字符串,有一些约束条件,两个位置要相同,有一些是问号,求最后有多少种方案回文? 分析: ...
- 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. ...
随机推荐
- Thunder团队第七周 - Scrum会议3
Scrum会议3 小组名称:Thunder 项目名称:i阅app Scrum Master:李传康 工作照片: 参会成员: 王航:http://www.cnblogs.com/wangh013/ 李传 ...
- 跨域写cookie
假设a站想往b站写cookie,那么目前有两种方案,参考如下: 第一种(使用jsonp): a站js代码如下: $.ajax({ url: 'http://www.b.com/jsonp.jsp?do ...
- 【Leetcode】179. Largest Number
Given a list of non negative integers, arrange them such that they form the largest number. For exam ...
- PAT 甲级 1027 Colors in Mars
https://pintia.cn/problem-sets/994805342720868352/problems/994805470349344768 People in Mars represe ...
- FastReport.Net 无限页高(连续纸小票)
using System; using System.Collections; using System.Collections.Generic; using System.ComponentMode ...
- Java知识点整理(三)
如何设计出高可用的分布式架构 分布式架构 CDN简介 分布式缓存和本地缓存区别 高并发场景常用技术解决方案 JVM优化示例 Docker和JVM区别 Java开发人员需要注意的五大Docker误区 D ...
- 【前端学习笔记01】JavaScript源生判断数据类型的方法
原始类型(值类型):Undefined.Null.Number.String.Boolean: 对象类型(引用类型):Object: typeof 可以识别标准类型,null外(返回Object): ...
- 迭代器 每迭代一次 指针往下面移动一次 除非JVM回收了内存 否则 他的指针不会回到原地
迭代器 每迭代一次 指针往下面移动一次 除非JVM回收了内存 否则 他的指针不会回到原地
- bzoj1923[Sdoi2010]外星千足虫(高斯消元)
Description Input 第一行是两个正整数 N, M. 接下来 M行,按顺序给出 Charles 这M次使用“点足机”的统计结果.每行 包含一个“01”串和一个数字,用一个空格隔开.“01 ...
- 【bzoj3518】点组计数 欧拉函数(欧拉反演)
题目描述 平面上摆放着一个n*m的点阵(下图所示是一个3*4的点阵).Curimit想知道有多少三点组(a,b,c)满足以a,b,c三点共线.这里a,b,c是不同的3个点,其顺序无关紧要.(即(a,b ...