倍增LCA(bzoj 3732: Network)

本文解析了一道关于图论的竞赛题目,通过构建最小生成树并利用倍增法快速求解两点间路径上的最大边权值,介绍了算法实现的具体过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3732: Network

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 1836   Solved: 868
[ Submit][ Status][ Discuss]

Description

给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。 

图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000).

现在有 K个询问 (1 < = K < = 20,000)。 

每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Input

第一行: N, M, K。 
第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。 
第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Output

 对每个询问,输出最长的边最小值是多少。

Sample Input

6 6 8
1 2 5
2 3 4
3 4 3
1 4 8
2 5 7
4 6 2
1 2
1 3
1 4
2 3
2 4
5 1
6 2
6 1

Sample Output

5
5
5
4
4
7
4
5


题目要两点之间最长的那条路尽可能的短

那么这条最短的“最长路”一定在最小生成树上,这个用反证法很好证明

这样就简单多了,因为是树,所以两点直接的路径唯一,每次只要查询路径中的最长边就好了

每次爆搜是不可能的,树链剖分又太麻烦(这都是废话)

倍增吧……


那。。怎么倍增?

先考虑暴力的方法:

先搜一遍预处理所有节点的父亲fa[x]和深度dep[x]

那么对于两点x和y,每次让更深的那个点向父亲爬就好了,最后两点一定会在最近公共祖先相遇,可这样超时

而倍增其实很简单,每个节点除了存下它的父亲以外,还存下它父亲的父亲、它父亲的父亲的父亲的父亲……

也就是说fa[x][j]存下x点的第2^j辈祖宗,例如fa[152][3]就是从节点152往上的第8个节点

递推式:fa[i][j] = fa[fa[i][j-1]][j-1];

那。。怎么爬捏?

步骤①:先让更深的那个节点往上爬,直到它们深度相同(有可能此时两个节点刚好相遇)

②:两个同时爬就好,如果它们的第2^j辈祖宗一样,则说明它们的最近公共祖先在第2^j之前;

如果它们的第2^j辈祖宗不一样,则让它们同时向上爬2^j步!

是不是很简单?


#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
typedef struct Road
{
	int u, v;
	int len;
	bool operator < (const Road &b) const
	{
		if(len<b.len)
			return 1;
		return 0;
	}
}Road;
Road s[30005], temp;
vector<Road> G[15005];
int ufs[15005], fa[15100][20], bet[15100][20], deep[15100];
int Find(int x)
{
	if(ufs[x]==0)
		return x;
	return ufs[x] = Find(ufs[x]);
}
void Sech(int x)
{
	int i;
	deep[x] = deep[fa[x][0]]+1;				//预处理每个节点的深度和它的父亲
	for(i=0;i<G[x].size();i++)
	{
		temp = G[x][i];
		if(temp.v==fa[x][0])
			continue;
		fa[temp.v][0] = x;
		bet[temp.v][0] = temp.len;
		Sech(temp.v);
	}
}
int Query(int x, int y)
{
	int j, ans = 0;
	if(deep[x]<deep[y])
		swap(x, y);
	for(j=14;j>=0;j--)			//①:先让更深的那个节点往上爬,直到它们深度相同(有可能此时两个节点刚好相遇)
	{
		if(deep[fa[x][j]]>=deep[y])
		{
			ans = max(ans, bet[x][j]);
			x = fa[x][j];
		}
	}
	if(x==y)
		return ans;
	for(j=14;j>=0;j--)					//②:两个同时爬
	{
		if(fa[x][j]!=fa[y][j])
		{
			ans = max(ans, bet[x][j]);
			ans = max(ans, bet[y][j]);
			x = fa[x][j];
			y = fa[y][j];
		}
	}
	ans = max(ans, bet[x][0]);
	ans = max(ans, bet[y][0]);
	return ans;
}
int main(void)
{
	int n, m, k, i, j, t1, t2, x, y;
	scanf("%d%d%d", &n, &m, &k);
	for(i=1;i<=m;i++)
		scanf("%d%d%d", &s[i].u, &s[i].v, &s[i].len);
	sort(s+1, s+m+1);
	for(i=1;i<=m;i++)
	{
		t1 = Find(s[i].u);
		t2 = Find(s[i].v);
		if(t1!=t2)
		{
			ufs[t1] = t2;
			temp = s[i];
			G[s[i].u].push_back(temp);
			temp.u = s[i].v, temp.v = s[i].u;
			G[s[i].v].push_back(temp);
		}
	}
	Sech(1);
	for(j=1;j<=14;j++)
	{
		for(i=1;i<=n;i++)					//倍增
		{
			fa[i][j] = fa[fa[i][j-1]][j-1];
			bet[i][j] = max(bet[i][j-1], bet[fa[i][j-1]][j-1]);
		}
	}
	for(i=1;i<=k;i++)
	{
		scanf("%d%d", &x, &y);
		printf("%d\n", Query(x, y));
	}
}




内容概要:本文探讨了在MATLAB/SimuLink环境中进行三相STATCOM(静态同步补偿器)无功补偿的技术方法及其仿真过程。首先介绍了STATCOM作为无功功率补偿装置的工作原理,即通过调节交流电压的幅值和相位来实现对无功功率的有效管理。接着详细描述了在MATLAB/SimuLink平台下构建三相STATCOM仿真模型的具体步骤,包括创建新模型、添加电源和负载、搭建主电路、加入控制模块以及完成整个电路的连接。然后阐述了如何通过对STATCOM输出电压和电流的精确调控达到无功补偿的目的,并展示了具体的仿真结果分析方法,如读取仿真数据、提取关键参数、绘制无功功率变化曲线等。最后指出,这种技术可以显著提升电力系统的稳定性与电能质量,展望了STATCOM在未来的发展潜力。 适合人群:电气工程专业学生、从事电力系统相关工作的技术人员、希望深入了解无功补偿技术的研究人员。 使用场景及目标:适用于想要掌握MATLAB/SimuLink软件操作技能的人群,特别是那些专注于电力电子领域的从业者;旨在帮助他们学会建立复杂的电力系统仿真模型,以便更好地理解STATCOM的工作机制,进而优化实际项目中的无功补偿方案。 其他说明:文中提供的实例代码可以帮助读者直观地了解如何从零开始构建一个完整的三相STATCOM仿真环境,并通过图形化的方式展示无功补偿的效果,便于进一步的学习与研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值