Karaoke Meetup
时间限制: 1 Sec 内存限制: 128 MB
题目描述
The judges of the South Pacific Programming Contest are planning their next secret karaoke meetup and are looking for a place to hold it. Last time, they asked Timothy to pick the location, but of course, he just picked somewhere really close to his house, and far from everyone else’s! This year, you would like to pick a meeting location that is fair.
All the judges live in the same city. The city consists of various locations in which the meeting could be held and roads that connect pairs of locations.
The city is built such that for each pair of locations, there is exactly one path between them. Each road has a length and can be used to travel in either direction. You consider a meeting point fair if the distances from each of the judges’ houses are similar. For each location, its fairness score is the ratio A/B, where A is the minimum distance from the location to any judges’ house and B is the largest distance. What is the maximum fairness score for all vertices?
输入
The first line contains two integers n (2 ≤ n ≤ 200 000), which is the number of locations in the city, and k (2 ≤ k ≤ n), which is the number of judges.
The next k lines describe the location of the judges’ houses. Each of these lines contains a single integer L (1 ≤ L ≤ n), which is the location of this judge’s house. No two judges live at the same location.
The next n − 1 lines describe the roads in the city. Each of these lines contains three integers u (1 ≤ u ≤ n), v (1 ≤ v ≤ n), and w (1 ≤ w ≤ 109), which denotes a road between locations u and v with a length of w.
输出
Display the maximum fairness score as a reduced fraction.
样例输入
样例1
1 2 3 4 5 |
3 2 2 3 1 2 1 1 3 1 |
样例2
1 2 3 4 |
2 2 1 2 1 2 10 |
样例3
1 2 3 4 5 6 7 8 |
5 3 5 2 4 3 1 1 1 4 1 1 2 1 3 5 1 |
样例4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
10 4 1 5 8 9 3 4 5 3 2 20 4 9 5 2 8 6 6 2 3 5 7 7 10 2 4 4 1 17 7 2 5 |
样例输出
样例1
1 |
1/1 |
样例2
1 |
0/1 |
样例3
1 |
1/2 |
样例4
1 |
5/16 |
题解
化用树形dp求树上每个点可以到达的最远距离,p[x][0]表示以x为根向下可以到达的最远距离(f[x][0])以及从哪个孩子转移过来,p[x][1]表示以x为根向下可以到达的“次远距离”以及从哪个孩子转移过来(并不是严格意义上的次远距离,要从和最远不同的点转移过来);f[x][1]表示从x向上(向父亲方向)可以到达的最远距离。
最短距离也可以通过树形dp来求,对于这个题,可以添加一个超级源点,把树化为图求最短路。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
#pragma GCC optimize(3,"Ofast","inline") #include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 200009; struct Edge { Edge(){} Edge(int p, LL d): p(p), d(d){} int p; LL d; }; struct Node { Node(){} Node(int x, LL d): x(x), d(d){} int x; LL d; bool operator < (const Node&a) const { return d > a.d; } }; int T, n, m, fa[N]; LL min_d[N], max_d[N], f[N][2]; bool is_judge[N], flag[N]; vector<Edge> g[N]; Node p[N][2]; template<typename T> T read() { T num = 0; char c; bool flag = 0; while((c=getchar())==' ' || c=='\n' || c=='\r'); if(c=='-') flag = 1; else num = c - '0'; while(isdigit(c=getchar())) num = num * 10 + c - '0'; return flag ? -num : num; } // 求最小距离,加一个源点0,树化为图 void dijkstra(int x) { memset(min_d, 0x3f, sizeof(min_d)); priority_queue<Node> q; q.push(Node(x, 0)); min_d[0] = 0; while(!q.empty()) { Node now = q.top(); q.pop(); for(auto i:g[now.x]) { if(min_d[now.x] + i.d >= min_d[i.p]) continue; min_d[i.p] = min_d[now.x] + i.d; q.push(Node(i.p, min_d[i.p])); } } } // 求每棵子树的根所能到达的最远距离 bool dfs1(int x) { flag[x] = 0; for (auto i:g[x]) { if(i.p == fa[x]) continue; fa[i.p] = x; if(!dfs1(i.p)) continue; flag[x] = 1; f[x][0] = max(f[x][0], f[i.p][0] + i.d); if(f[i.p][0] + i.d > p[x][0].d) p[x][1] = p[x][0], p[x][0] = Node(i.p, f[i.p][0] + i.d); else if(f[i.p][0] + i.d > p[x][1].d) p[x][1] = Node(i.p, f[i.p][0] + i.d); } flag[x] |= is_judge[x]; return flag[x]; } // 从父亲向孩子转移求能到达的最远距离,即求得实际最远距离 void dfs2(int x, bool passed, LL d) { passed |= is_judge[x]; if(passed) f[x][1] = max(f[x][1], f[fa[x]][1] + d); if(p[fa[x]][0].x != x && (flag[p[fa[x]][0].x] || is_judge[x] || is_judge[fa[x]])) { if(p[fa[x]][0].d + d > f[x][1]) f[x][1] = p[fa[x]][0].d + d, passed = 1; } else if(flag[p[fa[x]][1].x] || is_judge[x] || is_judge[fa[x]]) { if(p[fa[x]][1].d + d > f[x][1]) f[x][1] = p[fa[x]][1].d + d, passed = 1; } for (auto i:g[x]) if(i.p != fa[x]) dfs2(i.p, passed, i.d); max_d[x] = max(f[x][0], f[x][1]); } LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a % b); } int main(int argc, char const *argv[]) { #ifndef ONLINE_JUDGE freopen("input.in", "r", stdin); freopen("output.out", "w", stdout); #endif n = read<int>(); m = read<int>(); for (int i = 1; i <= m; i++) is_judge[read<int>()] = 1; for (int i = 1; i < n; i++) { int u = read<int>(), v = read<int>(); LL w = read<LL>(); g[u].push_back(Edge(v, w)); g[v].push_back(Edge(u, w)); } // 求最远距离 dfs1(1); dfs2(1, 0, 0); // 加超级源 for (int i = 1; i <= n; i++) { if(!is_judge[i]) continue; g[0].push_back(Edge(i, 0)); g[i].push_back(Edge(0, 0)); } // 求最短距离 dijkstra(0); // 求最大比值 LL ans1 = 0, ans2 = 0; for (int i = 1; i <= n; i++) { if(ans1 * max_d[i] > min_d[i] * ans2) continue; ans1 = min_d[i]; ans2 = max_d[i]; } LL k = gcd(ans1, ans2); printf("%lld/%lld\n", ans1 / k, ans2 / k); return 0; } |
叨叨几句... NOTHING