P3128 [USACO15DEC]Max Flow P(LCA 树上差分)

传送门

刚学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;
} 
原文地址:https://www.cnblogs.com/pureayu/p/14972521.html