P2680
题目的大意就是走完m条路径所需要的最短时间(边权是时间), 其中我们可以把一条边的权值变成0(也就是题目所说的虫洞)。
可以考虑二分答案x,找到一条边,使得所有大于x的路径都经过这条边(差分维护),并且路径减去这条边的边权后小等于x,通过这样判定x是否可行。
1 #include <bits/stdc++.h>
2 #define ll long long
3 using namespace std;
4 const int N = 3e5 + 10;
5 int tot, head[N], to[N << 1], nxt[N << 1], edge[N << 1];
6 int n, m, fa[N][25], dep[N], dis[N], pre[N], num[N];
7 struct node {
8 int x, y, lca;
9 }q[N];
10 void add(int x, int y, int z) {
11 nxt[++ tot] = head[x], head[x] = tot, to[tot] = y, edge[tot] = z;
12 }
13 void dfs(int u, int f) {
14 dep[u] = dep[f] + 1;
15 fa[u][0] = f;
16 for (int i = 1; i <= 20; i ++)
17 fa[u][i] = fa[fa[u][i - 1]][i - 1];
18 for (int i = head[u]; i; i = nxt[i]) {
19 int v = to[i];
20 if (v == f) continue;
21 pre[v] = edge[i];//v所在这条边的边权
22 dis[v] = dis[u] + edge[i];
23 dfs(v, u);
24 }
25 }
26 int getlca(int x, int y) {
27 if (dep[x] < dep[y]) swap(x, y);
28 for (int i = 20; i >= 0; i --) {
29 if (dep[fa[x][i]] >= dep[y]) x = fa[x][i];
30 }
31 if (x == y) return x;
32 for (int i = 20; i >= 0; i --) {
33 if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
34 }
35 return fa[x][0];
36 }
37 int flag, cnt, maxn;
38 int judge(int u, int f, int cnt, int maxn) {//返回子树和
39 int k = num[u];
40 for (int i = head[u]; i; i = nxt[i]) {
41 int v = to[i];
42 if (v == f) continue;
43 k += judge(v, u, cnt, maxn);
44 }
45 if (k >= cnt && pre[u] >= maxn) flag = 1;
46 //所有>mid的边都经过u所在这条边i,且i的权值满足条件
47 return k;
48 }
49 bool check(ll mid) {
50 memset(num, 0, sizeof num);
51 maxn = cnt = flag = 0;
52 for (int i = 1; i <= m; i ++) {
53 int d = dis[q[i].x] + dis[q[i].y] - 2 * dis[q[i].lca];
54 if (d > mid) {
55 num[q[i].x] ++, num[q[i].y] ++, num[q[i].lca] -= 2;
56 cnt ++;
57 maxn = max(maxn, d);
58 }
59 }
60 if (!cnt) return 1; // !!!!!
61 judge(1, 0, cnt, maxn - mid);
62 return flag;
63 }
64 int main() {
65 scanf("%d %d", &n, &m);
66 for (int i = 1; i < n; i ++) {
67 int a, b, c;
68 scanf("%d %d %d", &a, &b, &c);
69 add(a, b, c), add(b, a, c);
70 }
71 dfs(1, 0);
72 for (int i = 1; i <= m; i ++) {
73 scanf("%d %d", &q[i].x, &q[i].y);
74 q[i].lca = getlca(q[i].x, q[i].y);
75 }
76 ll l = 0, r = 300000000;
77 while (l < r) {
78 ll mid = (l + r) >> 1;
79 if (check(mid)) r = mid;
80 else l = mid + 1;
81 }
82 printf("%lld\n", l);
83 return 0;
84 }
标签:

留言评论