题目链接
半年前写过,然而是照着别人的模板敲的,今天自己写一遍。
dfs序+LCA+二分+树上差分。
然而我又写了树链剖分,简单粗暴。
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 300030;
struct edge{
int v, t;
};
vector<edge> E[N];
int n, m;
int size[N], son[N], dep[N], fa[N], top[N], rank[N], idx, dis[N];
void dfs1(int u, int f) {
size[u] = 1; dep[u] = dep[fa[u] = f] + 1;
for (int i = 0; i < E[u].size(); i++) {
int &v = E[u][i].v, &t = E[u][i].t;
if (v == f) continue;
dis[v] = dis[u] + t;
dfs1(v, u);
size[u] += size[v];
if (size[son[u]] < size[v])
son[u] = v;
}
}
void dfs2(int u, int tp) {
top[u] = tp; rank[++idx] = u;
if (! son[u]) return;
dfs2(son[u], tp);
for (int i = 0; i < E[u].size(); i++) {
int &v = E[u][i].v;
if (v == fa[u] or v == son[u]) continue;
dfs2(v, v);
}
}
inline int getLca(int u, int v) {
int f1 = top[u], f2 = top[v];
while (f1 != f2) {
if (dep[f1] < dep[f2]) {
swap(u, v); swap(f1, f2);
}
u = fa[f1]; f1 = top[u];
}
return dep[u] < dep[v] ? u : v;
}
int g_u[N], g_v[N], cost[N], lca[N], cap;
inline void init() {
cin >> n >> m;
for (int i = 1; i < n; i++) {
int a, b, t;
scanf("%d%d%d", &a, &b, &t);
E[a].push_back((edge){b, t});
E[b].push_back((edge){a, t});
}
dfs1(1, 0);
dfs2(1, 1);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &g_u[i], &g_v[i]);
cost[i] = dis[g_u[i]] + dis[g_v[i]] - dis[lca[i] = getLca(g_u[i], g_v[i])] * 2;
cap = max(cap, cost[i]);
}
}
int cover[N];
inline bool judge(int ans) {
memset(cover, 0, sizeof(cover));
int cnt = 0, ret = 0;
for (int i = 1; i <= m; i++) if (cost[i] > ans) {
cover[g_u[i]]++; cover[g_v[i]]++; cover[lca[i]] -= 2, cnt++;
ret = max(ret, cost[i] - ans);
}
for (int i = n; i > 1; i--)
cover[fa[rank[i]]] += cover[rank[i]];
for (int i = 1; i <= n; i++)
if (cover[i] == cnt and dis[i] - dis[fa[i]] >= ret)
return true;
return false;
}
inline void work() {
int l = 0, r = cap;
while (l < r) {
int mid = l + r >> 1;
if (judge(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
}
int main() {
init();
work();
return 0;
}