给定一棵树,给出若干次修改操作以及少次查询操作
修改操作:给定两个点 u , v u,v u,v,将 u , v u,v u,v路径上所有的点权值 + k +k +k
查询操作:询问点 x x x的权值
思路:树上差分,要修改 u , v u,v u,v路径上的所有点,只需
f
[
u
]
+
=
k
f[u]+=k
f[u]+=k
f
[
v
]
+
=
k
f[v]+=k
f[v]+=k
f
[
l
c
a
(
u
,
v
)
]
−
=
k
f[lca(u,v)]-=k
f[lca(u,v)]−=k
f
[
f
a
t
h
e
r
[
l
c
a
(
u
,
v
)
]
]
−
=
k
f[father[lca(u,v)]]-=k
f[father[lca(u,v)]]−=k
点 x x x的权值就是以 x x x为根的子树的权值和(前缀和)。
由于查询的时候需要跑一边dfs,因此查询次数不能过多
AC代码:
struct node
{
int v, w, next;
} e[200010];
int head[50010];
int ct = 1;
void add(int u, int v)
{
e[ct].v = v;
e[ct].next = head[u];
head[u] = ct++;
}
int father[50010][32];
int depth[50010];
void dfs(int now, int dep, int fa)
{
depth[now] = dep;
father[now][0] = fa;
for (int i = 1; i <= 30 && father[now][i - 1]; i++)
father[now][i] = father[father[now][i - 1]][i - 1];
for (int i = head[now]; i; i = e[i].next)
if (e[i].v != fa)
dfs(e[i].v, dep + 1, now);
}
int lca(int u, int v)
{
if (depth[u] < depth[v])
swap(u, v);
int cha = depth[u] - depth[v];
for (int i = 0; i <= 30; i++)
if ((1 << i) & cha)
u = father[u][i];
if (u == v)
return u;
for (int i = 30; i >= 0; i--)
if (father[u][i] != father[v][i])
{
u = father[u][i];
v = father[v][i];
}
return father[u][0];
}
int delta[50010];
void chafen(int u, int v)
{
int fa = lca(u, v);
delta[father[fa][0]]--;
delta[fa]--;
delta[u]++;
delta[v]++;
}
int ans = 0;
int dfs2(int now, int fa)
{
int res = delta[now];
for (int i = head[now]; i; i = e[i].next)
if (fa != e[i].v)
res += dfs2(e[i].v, now);
ans = max(res, ans);
return res;
}
int main()
{
int n, k;
scanf("%d%d", &n, &k);
for (int i = 1; i < n; i++)
{
int temp1, temp2;
scanf("%d%d", &temp1, &temp2);
add(temp1, temp2);
add(temp2, temp1);
}
dfs(1, 1, 0);
for (int i = 1; i <= k; i++)
{
int temp1, temp2;
scanf("%d%d", &temp1, &temp2);
chafen(temp1, temp2);
}
dfs2(1, 0);
printf("%d\n", ans);
return 0;
}