树上差分(LUOGU3128)

这篇博客介绍了如何利用差分数组和倍增法求解路径上的权值最大值。首先定义了一个Edge结构体来存储图的边,然后通过dfs遍历构建倍增法求祖先的数组father和深度数组deep。接着,定义了插入函数用于处理差分数组,最后通过sum函数计算每个节点的差分数组之和并找出最大值。程序读入图的结构和需要插入的路径,输出最大路径权值。
摘要由CSDN通过智能技术生成
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = 1e8;
const int Max = 5e4 + 10;
const int Max2 = 5e3 + 10;
struct Edge{
	int to, next;
}edge[Max<<1]; 
int n, k;
int head[Max], tot; 
int lg[Max];				//log2 n 向下取整
int father[Max][25];		//倍增法求祖先
int deep[Max];				//记录深度
int val[Max];				//记录差分数组
int max_val; 
void add(int u, int v){
	edge[tot].to = v;
	edge[tot].next = head[u];
	head[u] = tot++;
}
void dfs(int now, int fa, int depth){
	deep[now] = depth;
	father[now][0] = fa; 
	for (int i = 1;i <= 20;i++)
		father[now][i] = father[father[now][i - 1]][i - 1]; 
	for (int i = head[now]; i != -1; i = edge[i].next){
		int v = edge[i].to;
		if (v != fa)
			dfs(v, now, depth + 1);
	}
} 
int lca(int a, int b){
	if (deep[a] < deep[b]) swap(a, b); 
	while (deep[a] != deep[b])	{
		a = father[a][lg[deep[a] - deep[b]]];
	} 
	if (a == b) return a; 
	for (int i = 20; i >= 0;i--){
		if (father[a][i] != father[b][i]){
			a = father[a][i];
			b = father[b][i];
		}
	}
	return father[a][0];
} 
void insert(int s, int e){		//差分核心所在
	val[s]++;val[e]++;			//起止均加上权值
	int Lca = lca(s, e);
	val[Lca]--;val[father[Lca][0]]--;
}
void sum(int now){				//求差分数组的和
	for (int i = head[now]; i != -1; i = edge[i].next){
		int v = edge[i].to;
		if (v != father[now][0]){
			sum(v);
			val[now] += val[v];
		}
	}
	max_val = max(max_val, val[now]);
} 
int main(){
	lg[0] = -1;
	for (int i = 1;i < Max;i++)
		lg[i] = 1 + lg[i >> 1];
	while (scanf("%d%d", &n, &k) != EOF){
		memset(head, -1, sizeof(head));tot = 0;
		memset(val, 0, sizeof(val));max_val = 0; 
		for(int i = 1,u,v;i < n ;i ++){
			scanf("%d%d", &u, &v);
			add(u, v);add(v, u);
		}
		dfs(1,0,1);			//根结点之上可能还有结点被标记
 		for(int i = 1,u,v ;i <= k ;i ++){
			scanf("%d%d", &u, &v);
			insert(u, v);
		}
		add(0, 1);
		sum(0);
		printf("%d\n", max_val);
	} 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值