[luoguP2680] 运输计划(lca + 二分 + 差分)

传送门

暴力做法 50 ~ 60

枚举删边,求最大路径长度的最小值。

其中最大路径长度运用到了lca

我们发现,求lca的过程已经不能优化了,那么看看枚举删边的过程能不能优化。

先把边按照权值排序,然后。。。

然而并没有什么卵用。

题解给出了一种二分

二分答案。

判断依据:

比当前答案大的路径长度如果有一个公共边,并且最大的路径减去这条公共边小于等于当前答案,那么当前答案就满足。

如果当前答案不满足,那么比他小的答案更不可能满足,因为都不小于等于当前答案,比当前答案小的更不可能。

接下来就是如何判断,num[i] 表示点 i 指向父亲的边被几条路径所共有。

那么只需要 num[x]++, num[y]++, num[lca(x, y)] -= 2

最后dfs一遍求树上前缀和即可。

然后在 (num[i] == 比当前答案大的边的条数) 中找最大的边

然后判断就可以了

但是就是一个点超时,无语,把倍增改成tarjan也是超时,蛋疼。

——代码

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #define max(x, y) ((x) > (y) ? (x) : (y))
  6 #define MAXN 300001
  7 
  8 int n, m, cnt, qcnt;
  9 int num[MAXN], dis[MAXN], fv[MAXN], fa[MAXN], f[MAXN];
 10 int head[MAXN], to[MAXN << 1], val[MAXN << 1], next[MAXN << 1], qhead[MAXN], qnext[MAXN << 1], qto[MAXN << 1];
 11 //int f[MAXN][21], deep[MAXN];
 12 
 13 struct node
 14 {
 15     int qx, qy, lca, v;
 16 }q[MAXN];
 17 
 18 inline int read()
 19 {
 20     int x = 0, f = 1;
 21     char ch = getchar();
 22     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
 23     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
 24     return x * f;
 25 }
 26 
 27 inline void add(int x, int y, int z)
 28 {
 29     to[cnt] = y;
 30     val[cnt] = z;
 31     next[cnt] = head[x];
 32     head[x] = cnt++;
 33 }
 34 
 35 inline void addq(int x, int y)
 36 {
 37     qto[qcnt] = y;
 38     qnext[qcnt] = qhead[x];
 39     qhead[x] = qcnt++;
 40 }
 41 
 42 /*inline void dfs(int u)
 43 {
 44     int i, v;
 45     deep[u] = deep[f[u][0]] + 1;
 46     for(i = 0; f[u][i]; i++) f[u][i + 1] = f[f[u][i]][i];
 47     for(i = head[u]; i ^ -1; i = next[i])
 48     {
 49         v = to[i];
 50         if(!deep[v]) fv[v] = val[i], dis[v] = dis[u] + val[i], f[v][0] = u, dfs(v);
 51     }
 52 }
 53 
 54 inline int Lca(int x, int y)
 55 {
 56     int i;
 57     if(deep[x] < deep[y]) x ^= y ^= x ^= y;
 58     for(i = 18; i >= 0; i--)
 59         if(deep[f[x][i]] >= deep[y])
 60             x = f[x][i];
 61     if(x == y) return x;
 62     for(i = 18; i >= 0; i--)
 63         if(f[x][i] ^ f[y][i])
 64             x = f[x][i], y = f[y][i];
 65     return f[x][0];
 66 }*/ 
 67 
 68 inline int find(int x)
 69 {
 70     return x == fa[x] ? x : fa[x] = find(fa[x]);
 71 }
 72 
 73 inline void dfs(int u)
 74 {
 75     int i, v, x;
 76     fa[u] = u;
 77     for(i = head[u]; i ^ -1; i = next[i])
 78     {
 79         v = to[i];
 80         if(f[u] ^ v) f[v] = u, dis[v] = dis[u] + val[i], fv[v] = val[i], dfs(v);
 81     }
 82     for(i = qhead[u]; i ^ -1; i = qnext[i])
 83     {
 84         v = qto[i];
 85         if(f[x = u ^ q[v].qx ^ q[v].qy] || x == 1) q[v].lca = find(x);
 86     }
 87     fa[u] = f[u];
 88 }
 89 
 90 inline void dfs1(int u)
 91 {
 92     int i, v;
 93     for(i = head[u]; i ^ -1; i = next[i])
 94     {
 95         v = to[i];
 96         if(v ^ f[u]) dfs1(v), num[u] += num[v];
 97     }
 98 }
 99 
100 inline bool pd(int sum)
101 {
102     int i, x = 1, y = m, mid, ans, value = 0;
103     memset(num, 0, sizeof(num));
104     while(x <= y)
105     {
106         mid = (x + y) >> 1;
107         if(q[mid].v <= sum) x = mid + 1;
108         else ans = mid, y = mid - 1;
109     }
110     for(i = ans; i <= m; i++) num[q[i].qx]++, num[q[i].qy]++, num[q[i].lca] -= 2;
111     dfs1(1);
112     for(i = 1; i <= n; i++)
113         if(num[i] == m - ans + 1)
114             value = max(value, fv[i]);
115     if(!value) return 0;
116     return q[m].v - value <= sum;
117 }
118 
119 inline bool cmp(node x, node y)
120 {
121     return x.v < y.v;
122 }
123 
124 int main()
125 {
126     int i, x, y, z, mid, ans = 0;
127     n = read();
128     m = read();
129     memset(head, -1, sizeof(head));
130     memset(qhead, -1, sizeof(qhead));
131     for(i = 1; i < n; i++)
132     {
133         x = read();
134         y = read();
135         z = read();
136         add(x, y, z);
137         add(y, x, z);
138     }
139     //dfs(1);
140     for(i = 1; i <= m; i++)
141     {
142         q[i].qx = read();
143         q[i].qy = read();
144         addq(q[i].qx, i);
145         addq(q[i].qy, i);
146         //q[i].lca = Lca(q[i].qx, q[i].qy);
147         //q[i].v = dis[q[i].qx] + dis[q[i].qy] - (dis[q[i].lca] << 1);
148     }
149     dfs(1);
150     x = y = 0;
151     for(i = 1; i <= m; i++) q[i].v = dis[q[i].qx] + dis[q[i].qy] - (dis[q[i].lca] << 1), y = max(y, q[i].v);
152     std::sort(q + 1, q + m + 1, cmp);
153     while(x <= y)
154     {
155         mid = (x + y) >> 1;
156         if(pd(mid)) ans = mid, y = mid - 1;
157         else x = mid + 1;
158     }
159     printf("%d
", ans);
160     return 0;
161 }
View Code

还留有倍增的痕迹。

原文地址:https://www.cnblogs.com/zhenghaotian/p/6924331.html