刚学LCA,做一下树上差分的题目。
很明显的一道树上差分的题目且是点差分,从差分数组的思想延伸到树上差分,对于树上的一条路,假设要将a-b路径上的所有点都加上一个值,那么只需要在a点和b点加上这个值,并且在两者的LCA处及LCA的父节点上都减去这个值就可以了,因为最后在进行由下到上的递归过程中,LCA节点会被重复计算两次,这样就能保证只计算一次。
由于这道题要求的是整张图上的最大值,只需要从根节点遍历一遍同时维护一个最大值就可以了。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 2e5 + 10;
struct Edge{
int v, next;
}edge[M];
int dep[N], fa[N][22], maxn = -1;
int tot, head[N], mark[N];
void add(int u, int v){
edge[tot].next = head[u];
edge[tot].v = v;
head[u] = tot ++;
}
void dfs(int now, int pre){
dep[now] = dep[pre] + 1;
fa[now][0] = pre;
for(int i = head[now]; i != -1; i = edge[i].next){
int v = edge[i].v;
if(v != pre)
dfs(v, now);
}
}
int getlca(int u, int v){
if(dep[u] < dep[v])
swap(u, v);
while(dep[u] > dep[v])
u = fa[u][(int)log2(dep[u] - dep[v])];
if(u == v)
return u;
for(int i = 20; i >= 0; i --)
if(fa[u][i] != fa[v][i])
u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
int dfslca(int node, int pre){
for(int i = head[node]; i != -1; i = edge[i].next){
int v = edge[i].v;
if(v != pre){
dfslca(v, node);
mark[node] += mark[v];
}
}
maxn = max(maxn, mark[node]);
}
int main(){
int n, k;
scanf("%d%d", &n, &k);
memset(head, -1, sizeof head);
for(int i = 1; i < n; i ++){
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs(1, 0);
for(int j = 1; j <= 20; j ++)
for(int i = 1; i <= n; i ++)
fa[i][j] = fa[fa[i][j - 1]][j - 1];
for(int i = 1; i <= k; i ++){
int a, b;
scanf("%d%d", &a, &b);
int lca = getlca(a, b);
mark[a] ++;
mark[b] ++;
mark[lca] --;
mark[fa[lca][0]] --;
}
maxn = -1;
cout << dfslca(1, -1) << endl;
return 0;
}