P2680 [NOIP2015 提高组] 运输计划 (树上差分-边差分)

乎语百科 271 0

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 } 

标签:

留言评论

  • 这篇文章还没有收到评论,赶紧来抢沙发吧~