任重而道远
Description
公元 2044 年,人类进入了宇宙纪元。L 国有 n 个星球,还有 n?1 条双向航道,每条航道建立在两个星球之间,
这 n-1 条航道连通了 L 国的所有星球。小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如
:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间
的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。为了鼓励科技
创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫
洞不消耗时间。在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输
计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。如
果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多
少?
Input
第一行包括两个正整数 n,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。
接下来 n-1 行描述航道的建设情况,其中第 i 行包含三个整数 ai,bi 和 ti,
表示第 i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。
接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个运输计划是从 uj 号星球飞往 vj号星球。
数据保证 1≤ui,vi≤n ,n,m<=300000
数据保证 1≤ai,bi≤n 且 0≤ti≤1000。
Output
输出文件只包含一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。
Sample Input
6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
Sample Output
11
将第 1 条航道改造成虫洞: 则三个计划耗时分别为:11,12,11,故需要花费的时间为 12。
将第 2 条航道改造成虫洞: 则三个计划耗时分别为:7,15,11,故需要花费的时间为 15。
将第 3 条航道改造成虫洞: 则三个计划耗时分别为:4,8,11,故需要花费的时间为 11。
将第 4 条航道改造成虫洞: 则三个计划耗时分别为:11,15,5,故需要花费的时间为 15。
将第 5 条航道改造成虫洞: 则三个计划耗时分别为:11,10,6,故需要花费的时间为 11。
故将第 3 条或第 5 条航道改造成虫洞均可使得完成阶段性工作的耗时最短,需要花费的时间为 11。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 3e5 + 5, P = 22;
struct Edge {int tov, nxt, val;} e[N << 1];
struct Node {
int u, v, lca, val;
bool operator < (const Node &a) const {
return val > a.val;
}
}q[N];
int head[N], anc[N][P + 2], w[N][P + 2], s[N], dep[N], dis[N];
int n, m, num;
int read () {
int x = 0, f = 0; char c = getchar ();
while (!isdigit (c)) f |= (c == '-'), c = getchar ();
while (isdigit (c)) x = x * 10 + c - '0', c = getchar ();
return f ? -x : x;
}
void add_edge (int u, int v, int val) {
e[++num] = (Edge) {v, head[u], val}, head[u] = num;
e[++num] = (Edge) {u, head[v], val}, head[v] = num;
}
void dfs (int u) {
dep[u] = dep[anc[u][0]] + 1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].tov;
if (v == anc[u][0]) continue;
anc[v][0] = u, dis[v] = dis[u] + e[i].val;
dfs (v);
}
}
void init () {
dfs (1);
for (int p = 1; p <= P; p++)
for (int u = 1; u <= n; u++)
anc[u][p] = anc[anc[u][p - 1]][p - 1];
}
int Lca (int u, int v) {
if (dep[u] < dep[v]) swap (u, v);
for (int p = P; p >= 0; p--)
if (dep[anc[u][p]] >= dep[v]) u = anc[u][p];
if (u == v) return u;
for (int p = P; p >= 0; p--)
if (anc[u][p] != anc[v][p]) {
u = anc[u][p];
v = anc[v][p];
}
return anc[u][0];
}
void get (int u) {
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].tov;
if (v == anc[u][0]) continue;
get (v);
s[u] += s[v];
}
}
bool check (int x) {
memset (s, 0, sizeof (s));
int tot = 0, sww = 0, f = 1, jud = 0;
for (int i = 1; q[i].val > x; i++) {
s[q[i].u]++, s[q[i].v]++;
s[q[i].lca] -= 2;
tot++;
}
get (1);
for (int i = 1; i <= n; i++)
if (s[i] == tot) {
sww = max (sww, dis[i] - dis[anc[i][0]]);
jud = 1;
}
if (!jud) return false;
for (int i = 1; i <= tot; i++)
if (q[i].val - sww > x) {
f = 0; break;
}
return f;
}
int main () {
n = read (), m = read ();
for (int i = 1; i < n; i++) {
int u = read (), v = read (), val = read ();
add_edge (u, v, val);
}
init ();
for (int i = 1; i <= m; i++) {
int u = read (), v = read ();
int ca = Lca (u, v);
q[i] = (Node) {u, v, ca, dis[u] + dis[v] - 2 * dis[ca]};
}
sort (q + 1, q + m + 1);
int lf = 0, rg = q[1].val;
while (lf <= rg) {
int mid = lf + rg >> 1;
if (check (mid)) rg = mid - 1;
else lf = mid + 1;
}
printf ("%d\n", lf);
return 0;
}