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 }
标签:NOIP2015,return,int,P2680,差分,mid,fa,maxn,cnt From: https://www.cnblogs.com/YHxo/p/16757289.html