题意
传送门 P3128 [USACO15DEC]Max Flow
题解
求树上被运输路线覆盖次数最多的点。考虑树上差分,倍增求
L
C
A
LCA
LCA,设路径的两个端点分别为
u
,
v
u,v
u,v,差分数组为
d
d
d,父节点数组为
p
a
r
par
par,则对于每一条路径
d
u
←
d
u
+
1
d_u\leftarrow d_u+1
du←du+1
d
v
←
d
v
+
1
d_v\leftarrow d_v+1
dv←dv+1
d
L
C
A
←
d
L
C
A
−
1
d_{LCA}\leftarrow d_{LCA}-1
dLCA←dLCA−1
d
p
a
r
[
L
C
A
]
←
d
p
a
r
[
L
C
A
]
−
1
d_{par[LCA]}\leftarrow d_{par[LCA]}-1
dpar[LCA]←dpar[LCA]−1 最后回溯从叶子节点计算前缀和,更新答案即可。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define maxlg 16
#define maxn 50005
int N, K, res, lg[maxn], dif[maxn], par[maxlg][maxn], dep[maxn];
vector<int> G[maxn];
void dfs(int p, int v, int d)
{
par[0][v] = p, dep[v] = d;
for (int i = 1; i <= lg[d]; ++i)
par[i][v] = par[i - 1][par[i - 1][v]];
for (int i = 0; i < (int)G[v].size(); ++i)
{
int u = G[v][i];
if (u != p)
dfs(v, u, d + 1);
}
}
int lca(int u, int v)
{
if (dep[u] > dep[v])
swap(u, v);
while (dep[v] > dep[u])
v = par[lg[dep[v] - dep[u]]][v];
if (u == v)
return v;
for (int i = lg[dep[v]]; i >= 0; --i)
{
if (par[i][v] != par[i][u])
v = par[i][v], u = par[i][u];
}
return par[0][v];
}
void sum(int p, int v)
{
for (int i = 0; i < (int)G[v].size(); ++i)
{
int u = G[v][i];
if (u != p)
{
sum(v, u);
dif[v] += dif[u];
}
}
res = max(res, dif[v]);
}
int main()
{
scanf("%d%d", &N, &K);
for (int i = 1; i < N; ++i)
{
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
lg[0] = -1;
for (int i = 1; i <= N; ++i)
lg[i] = lg[i - 1] + (1 << (lg[i - 1] + 1) == i);
dfs(0, 1, 0);
for (int i = 0; i < K; ++i)
{
int s, t;
scanf("%d%d", &s, &t);
int p = lca(s, t);
++dif[s], ++dif[t];
--dif[p], --dif[par[0][p]];
}
sum(0, 1);
printf("%d\n", res);
return 0;
}