题目链接
https://www.luogu.org/problemnew/show/P2680
这道题写着最短时间,那么完成的时间是所有时间中最长的
所以最大值最小可以想到二分答案
那么我就卡在了如果判定上……………………
我们仔细想想,我们可以把一条边的边权变为0
也就是说使得一些计划时间变短
那么我们可以把比ans大的计划全部记录下来
然后看有没有被这些计划共同覆盖的边,然后把这条边边为0之后,时间最长的计划还是不是大于ans
可以用树上差分算出覆盖次数
我开始的时候二分的r直接写3e8,然后有一个点被卡掉了,注意常数
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; const int MAXN = 3e5 + 10; const int MAXM = 20; struct Edge{ int to, w, next; }; Edge e[MAXN << 1]; int head[MAXN], d[MAXN], dis[MAXN], cnt[MAXN], tot; int f[MAXN][MAXM + 5], p[MAXN], n, m; struct plan { int u, v, lca, t; }a[MAXN]; void AddEdge(int from, int to, int w) { e[tot] = Edge{to, w, head[from]}; head[from] = tot++; } void read(int& x) { int f = 1; x = 0; char ch = getchar(); while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); } while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); } x *= f; } void dfs(int u, int fa) { for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if(v == fa) continue; dis[v] = dis[u] + e[i].w; d[v] = d[u] + 1; p[v] = e[i].w; f[v][0] = u; dfs(v, u); } } void get_lca() { f[1][0] = 1; dfs(1, -1); _for(j, 1, MAXM) _for(i, 1, n) f[i][j] = f[f[i][j-1]][j-1]; } int LCA(int u, int v) { if(d[u] < d[v]) swap(u, v); for(int j = MAXM; j >= 0; j--) if(d[f[u][j]] >= d[v]) u = f[u][j]; if(u == v) return u; for(int j = MAXM; j >= 0; j--) if(f[u][j] != f[v][j]) u = f[u][j], v = f[v][j]; return f[u][0]; } bool sum(int u, int fa, int maxt, int num, int ans) { for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if(v == fa) continue; if(sum(v, u, maxt, num, ans)) return true; cnt[u] += cnt[v]; } if(cnt[u] == num) return maxt - p[u] <= ans; return false; } bool check(int ans) { int maxt = 0, num = 0; memset(cnt, 0, sizeof(cnt)); _for(i, 1, m) if(a[i].t > ans) { cnt[a[i].u]++; cnt[a[i].v]++; cnt[a[i].lca] -= 2; maxt = max(maxt, a[i].t); num++; } return sum(1, -1, maxt, num, ans); } int main() { memset(head, -1, sizeof(head)); tot = 0; scanf("%d%d", &n, &m); REP(i, 1, n) { int u, v, w; read(u); read(v), read(w); AddEdge(u, v, w); AddEdge(v, u, w); } int l = -1, r; get_lca(); _for(i, 1, m) { int u, v; read(u); read(v); int lca = LCA(u, v); a[i] = plan{u, v, lca, dis[u] + dis[v] - 2 * dis[lca]}; r = max(r, a[i].t); } while(l + 1 < r) { int m = (l + r) >> 1; if(check(m)) r = m; else l = m; } printf("%d ", r); return 0; }