暴力做法 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 }
还留有倍增的痕迹。