用树链剖分求lca,二分答案树上差分判断。
时间复杂度$O(nlogn)$,n,m同阶。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 300003; int in() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = (k << 3) + (k << 1) + c - '0'; return k * fh; } struct QQ {int u, v, lca, len;} Q[N]; struct node {int nxt, to, w;} E[N << 1]; int n, m, cnt = 0, point[N], size[N], son[N], top[N], deep[N], fa[N]; int DFN[N], tot = 0, dis[N], fa_dis[N]; void ins(int u, int v, int w) { E[++cnt] = (node) {point[u], v, w}; point[u] = cnt; } void _(int x) { size[x] = 1; DFN[++tot] = x; for(int i = point[x]; i; i = E[i].nxt) if (E[i].to != fa[x]) { fa[E[i].to] = x; deep[E[i].to] = deep[x] + 1; dis[E[i].to] = dis[x] + E[i].w; fa_dis[E[i].to] = E[i].w; _(E[i].to); size[x] += size[E[i].to]; if (size[E[i].to] > size[son[x]]) son[x] = E[i].to; } } void __(int x) { if (!son[x]) return; top[son[x]] = top[x]; __(son[x]); for(int i = point[x]; i; i = E[i].nxt) if (E[i].to != son[x] && E[i].to != fa[x]) {top[E[i].to] = E[i].to; __(E[i].to);} } int LCA(int u, int v) { while (top[u] != top[v]) { if (deep[top[u]] < deep[top[v]]) swap(u, v); u = fa[top[u]]; } return deep[u] < deep[v] ? u : v; } int del[N], cont, maxnow; bool check(int s) { cont = 0; maxnow = 0; memset(del, 0, sizeof(int) * (n + 1)); for(int i = 1; i <= m; ++i) if (Q[i].len > s) { ++del[Q[i].u]; ++del[Q[i].v]; del[Q[i].lca] -= 2; ++cont; maxnow = max(maxnow, Q[i].len - s); } if (!cont) return true; for(int i = n; i > 1; --i) del[fa[DFN[i]]] += del[DFN[i]]; for(int i = 2; i <= n; ++i) if (fa_dis[i] >= maxnow && del[i] == cont) return true; return false; } int main() { n = in(); m = in(); int u, v, w; for(int i = 1; i < n; ++i) { u = in(); v = in(); w = in(); ins(u, v, w); ins(v, u, w); } _(1); top[1] = 1; __(1); int left = 0, right = 0, mid; for(int i = 1; i <= m; ++i) { Q[i].u = in(); Q[i].v = in(); Q[i].lca = LCA(Q[i].u, Q[i].v); Q[i].len = dis[Q[i].u] + dis[Q[i].v] - (dis[Q[i].lca] << 1); right = max(right, Q[i].len); } while (left < right) { mid = (left + right) >> 1; if (check(mid)) right = mid; else left = mid + 1; } printf("%d ", left); return 0; }
QwQ