「LCA + 树上差分」[USACO15DEC]最大流Max Flow
[USACO15DEC]最大流Max Flow
原题链接 最大流Max Flow
题目大意
给你 \(n - 1\) 条边,再给你 \(m\) 个操作,每次操作两个数 \(u, v\) 表示,\(u, v\) 的最短路径上每个点都加上\(1\)
题目题解
树上差分的经典题 (一直想学树上差分,今天终于会了quq),我们修改时,使\(power_u\)++ ,\(power_v\)++,\(power_{lca(u,v)}\)--,\(power_{f[lca(u,v)][0]}\)-- 就可以了
接下来就是代码..xx
//#define fre yes
#include <cstdio>
#include <cstring>
#include <iostream>
int n, m;
const int N = 50005;
int head[N << 1], to[N << 1], ver[N << 1];
int f[N][22], lg[N], depth[N], power[N];
int tot;
void addedge(int x, int y) {
ver[tot] = y;
to[tot] = head[x];
head[x] = tot++;
}
void dfs(int x, int fa) {
depth[x] = depth[fa] + 1;
f[x][0] = fa;
for (int i = 1; (1 << i) <= depth[x]; i++) {
f[x][i] = f[f[x][i - 1]][i - 1];
}
for (int i = head[x]; ~i; i = to[i]) {
int v = ver[i];
if(v != fa) {
dfs(v, x);
}
}
}
int ans;
void sum(int u, int fa) {
for (int i = head[u]; ~i; i = to[i]) {
int v = ver[i];
if(v != fa) {
sum(v, u);
power[u] += power[v];
}
} ans = std::max(ans, power[u]);
}
int lca(int u, int v) {
if(depth[u] < depth[v]) {
std::swap(u, v);
}
while(depth[u] > depth[v]) {
u = f[u][lg[depth[u] - depth[v]] - 1];
}
if(u == v) return u;
for (int i = lg[depth[u]] - 1; i >= 0; i--) {
if(f[u][i] != f[v][i]) {
u = f[u][i];
v = f[v][i];
}
} return f[u][0];
}
int main() {
memset(head, -1, sizeof(head));
scanf("%d %d", &n, &m);
for (int i = 1; i <= n - 1; i++) {
int u, v;
scanf("%d %d", &u, &v);
addedge(u, v);
addedge(v, u);
}
dfs(1, -1);
for (int i = 1; i <= n; i++) {
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
}
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d %d", &x, &y);
int lc = lca(x, y);
++power[x]; ++power[y]; --power[lc]; --power[f[lc][0]];
}
sum(1, -1);
printf("%d\n", ans);
return 0;
}