kruskal重构树

news2024/9/22 1:24:52

一,定义

kruskal是求最小生成树的一种算法。最小生成树

但是这种结合并查集的特殊方法给了他许多特殊的性质。可以用于解决树上瓶颈边权之类的问题

结合这种算法而诞生的就是——kruskal重构树

二,建树思路及其性质

kruskal求最小生成树是将边权小的边先连起来。而重构树则是同理,他把当前最小边抽象为一个虚点(虚点的值为该边权值),然后把这条边对应的两个不同集合视为左右儿子,将集合与该虚点建边

 建树后我们很清晰地发现它有如下性质

  1. 是一颗二叉树
  2. 虚点有n-1个,且值随着树的建立不断变大(因为是从小边建到大边嘛)
  3. 父节点都是虚点,叶子节点都是原来图中的点
  4. 如果我们从图中任意x点到y点,那么他们路过的最大边权边就是他们的重构树lca虚点val值
  5. 换句话说:原图中x到y的所有简单路径中最大边权的最小值是val[lca(x,y)](因为所有路径中,每条边都最小的肯定是最小生成树的,那么最小中的最大边权也肯定是所有路径中最大边权中最小的)==最小生成树上两个点之间的简单路径上的最大值= Kruskal 重构树上两点之间的 LCA 的权值

例题一:P1967 [NOIP2013 提高组] 货车运输 

思路:如果我们建最大生成树,那么lca(x,y)就是所有路径能通过的最小边权的最大值

#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define endl             "\n"
#define int              long long
#define endll            endl<<endl
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
//---------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------//
//double 型memset最大127,最小128
const int INF = 0x3f3f3f3f;         //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 2e5 + 10;
struct node
{
	int u,v,w;
	bool operator<(const node&k)const
	{
		return w>k.w;
	}
} b[N<<1];
vector<int>edge[N<<1];
int fa[N],val[N<<1],dep[N],pre[N][32];

int find(int x)//并查集
{
	if(fa[x]!=x)fa[x]=find(fa[x]);
	return fa[x];
}

void dfs(int u,int f)//遍历重构树建立深度与预处理lca
{
	dep[u]=dep[f]+1;
	pre[u][0]=f;
	for(int i=1; i<=20; ++i)pre[u][i]=pre[pre[u][i-1]][i-1];
	for(auto v:edge[u])if(v!=f)dfs(v,u);
}

int LCA(int u,int v)
{
	if(dep[u]<dep[v])swap(u,v);
	if(dep[u]>dep[v])
		{
			int k=log2(dep[u]-dep[v]);
			for(int i=k; i>=0; --i)if(dep[pre[u][i]]>=dep[v])u=pre[u][i];
		}
	if(u==v)return u;
	int k=log2(dep[u]);
	for(int i=k; i>=0; --i)if(pre[u][i]!=pre[v][i])u=pre[u][i],v=pre[v][i];
	return pre[u][0];
}

void mysolve()
{
	int n,m;
	cin>>n>>m;
	for(int i=1; i<=2*n; ++i)fa[i]=i;
	for(int i=1; i<=m; ++i)cin>>b[i].u>>b[i].v>>b[i].w;
	sort(b+1,b+1+m);
	int cnt=n;
	for(int i=1; i<=m; ++i)//重构
		{
			int fu=find(b[i].u),fv=find(b[i].v);
			if(fu!=fv)
				{
					val[++cnt]=b[i].w;
					fa[fu]=fa[fv]=cnt;
					edge[cnt].push_back(fu),edge[cnt].push_back(fv);
				}
		}
	for(int i=cnt; i>n; --i)if(fa[i]==i)dfs(i,i);//可能是森林
	int q,x,y;
	cin>>q;
	while(q--)
		{
			cin>>x>>y;
			if(find(x)!=find(y))cout<<-1<<endl;
			else cout<<val[LCA(x,y)]<<endl;
		}

}
int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t=1;
	//cin >> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

例题二:P4768 [NOI2018] 归程 

思路:

  1. 首先,我们容易想到,每次询问,只需要开车开到能靠近家(1点)位置,剩下走路即可
  2. 我们询问可以有logq的复杂度
  3. 那么我们如果先用dijksta预处理每个点到家的最短距离,然后我们重构树不是每个虚点子代的点表示只要你这个虚点我能来(我们建最大生成树),那么你的子节点我就能到达,所以这个虚点可以存储子树集合到达家的最小值。
  4. 那么我们每次 每次询问v点,尽可能跳到最大的祖先,剩下不行距离就是该祖先点存储的子树中到达家的最小距离。(能通过虚点说明子树是可以任意通过的)
#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define endl             "\n"
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;         //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 1e6 + 10;

struct node//kruskal的海拔
{
	int u,v,w;
	bool operator<(const node&k)const
	{
		return w>k.w;
	}
} b[N];

struct node1//最短路
{
	int next,to,w;
} edge[N];
int fa[N],pre[N][32],val[N],dis[N],head[N],num,cnt;
int dep[N];
vector<int>eg[N];//重构树的边

void add(int u,int v,int w)
{
	edge[++num].next=head[u];
	edge[num].to=v;
	edge[num].w=w;
	head[u]=num;
}

void init(int n)
{
	for(int i=1; i<=2*n; ++i)fa[i]=i,fa[n+i]=n+i,eg[i].clear(),head[i]=0;//注意,重构树建立后点变成两遍,所以开空间要开两倍,初始化也要
	num=0,cnt=n;
}

int find(int x)
{
	if(fa[x]!=x)fa[x]=find(fa[x]);
	return fa[x];
}

void dijkstra(int n)
{
	for(int i=1; i<=2*n; ++i)dis[i]=INF;//2n个点,包含虚点,跑dij不会碰到虚点(都没出生呢),一开始虚点显然离终点无限远
	dis[1]=0;
	priority_queue<pii,vector<pii>,greater<pii>>q;
	q.push({dis[1],1});
	while(!q.empty())
		{
			int u=q.top().second;
			q.pop();
			for(int i=head[u]; i; i=edge[i].next)
				{
					int v=edge[i].to,w=edge[i].w;
					if(dis[v]>dis[u]+w)
						{
							dis[v]=dis[u]+w;
							q.push({dis[v],v});
						}
				}
		}
}

void kruskal(int n,int m)
{
	sort(b+1,b+1+m);
	cnt=n;
	for(int i=1; i<=m; ++i)
		{
			int fu=find(b[i].u),fv=find(b[i].v);
			if(fu!=fv)
				{
					val[++cnt]=b[i].w;
					fa[fu]=fa[fv]=cnt;
					eg[cnt].push_back(fu),eg[cnt].push_back(fv);
				}
		}
}

void dfs(int u,int f)
{
	dep[u]=dep[f]+1;
	pre[u][0]=f;
	for(int i=1; i<=20; ++i)pre[u][i]=pre[pre[u][i-1]][i-1];
	for(auto v:eg[u])if(v!=f)
			{
				dfs(v,u);
				dis[u]=min(dis[v],dis[u]);//存储虚点的子树的最小距离
			}
}

void mysolve()
{
	int n,m;
	cin>>n>>m;
	init(n);
	int x,y,d,w;
	for(int i=1; i<=m; ++i)
		{
			cin>>x>>y>>d>>w;
			add(x,y,d),add(y,x,d);
			b[i].u=x,b[i].v=y,b[i].w=w;
		}
	dijkstra(n);
	kruskal(n,m);
	dfs(cnt,0);
	int q,k,s;
	cin>>q>>k>>s;
	int v,p,lantans=0;
	while(q--)
		{
			cin>>v>>p;
			v=(v+k*lantans-1)%n+1;
			p=(p+k*lantans)%(s+1);
			int h=log2(dep[v]);
			for(int i=h; i>=0; --i)
				if(dep[pre[v][i]]&&val[pre[v][i]]>p)v=pre[v][i];
			cout<<(lantans=dis[v])<<endl;
		}
}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t=1;
	cin >> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/416740.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【超详细】小白初探FME--获取等时圈

在规划分析过程中&#xff0c;往往会涉及等时圈的概念。什么是等时圈呢&#xff1f;小编帮你百度过了&#xff0c;网上的说法是&#xff1a;等时圈是指从某点出发&#xff0c;以某种交通方式在特定时间内能到达的距离覆盖的范围。比如我们在规划设计中接触到的15分钟生活圈就是…

HTML5支持的视频文件格式和音频文件格式有哪些?

在 HTML5 标准中, 我们有了新的 <audio> 和 <video> 标签, 分别可以引入视频和音频文件的标签 那么这些标签又可以支持哪些文件格式呢 ? 格式支持 视频文件格式 MP4&#xff1a;MPEG-4 Part 14&#xff0c;支持H.264编码。几乎所有的浏览器都支持该格式。 Web…

springboot+netty+mqtt实现

具体实现前言MQTT协议概念组成部分实现mqtt协议测试其他前言 首先说明一下&#xff0c;netty实现并封装了mqtt协议&#xff0c;同时也为其写好了编解码器&#xff0c;但是再了解并搭建之前&#xff0c;尤其是还不了解netty和mqtt的同学&#xff0c;必须要清楚一件事&#xff1…

2023MathorCup数学建模比赛的思路汇总帖

更新时间【4.13 19&#xff1a;45】ABCD均已更新&#xff0c;选题指导已更新&#xff0c;速看&#xff01;后续会出各题详细思路及代码&#xff01; 这里是小云的2023MathorCup数学建模比赛的思路汇总帖&#xff0c;比赛开始后将实时更新~ 竞赛共4道题目&#xff08;A题、B题…

ELF 文件格式 ------- 符号表

1. 符号的数据结构 typedef struct elf64_sym {Elf64_Word st_name; /* 该符号的名字在字符串表中的起始下标 */unsigned char st_info; /* 该符号的类型以及作用域信息 */unsigned char st_other; /* 暂未使用 */Elf64_Half st_shndx; /* 该符号所在的 section 的下标&…

IDEA安装spotbugs插件替代findbugs插件

相信最近想在IDEA上安装findbugs插件的朋友&#xff0c;遇到与我一样的问题&#xff0c;findbugs与IDEA不兼容&#xff1a; https://plugins.jetbrains.com/plugin/3847-findbugs-idea 主要是FindBugs插件已经不更新了&#xff0c;它最新版本停留在2016年发布的1.0.1&#xff0…

百度文心一言可以完胜ChatGPT的4点可能性

文心一言&#xff0c;百度全新一代知识增强大语言模型&#xff0c;文心大模型家族的新成员&#xff0c;能够与人对话互动&#xff0c;回答问题&#xff0c;协助创作&#xff0c;高效便捷地帮助人们获取信息、知识和灵感。但说实话&#xff0c;很多人拿他与ChatGPT相对比&#x…

RabbitMQ( 发布订阅模式 ==> DirectExchange)

本章目录&#xff1a; 何为DirectExchangeDirectExchange具体使用一、何为DirectExchange 在上一篇文章中&#xff0c;讲述了FanoutExchange&#xff0c;其中publish向交换机发送消息时&#xff0c;我们并没有指定routkingKey&#xff0c;如下图所示 我们看看官方文档 之前使…

【教学类-32-01】十二生肖1.0版(绘画+手工+排序+分类+玩牌)(中班:偏科学-数)

作品展示 背景需求——从数字到图片 最佳孩子们做Python纸类&#xff08;数学&#xff09;的频率比较高。但都是数字类&#xff08;加减法、门牌号、火车箱、电话号码等&#xff09;我想翻新花样&#xff0c;设计新的内容&#xff0c;就想到了水果图片、动物图片。 百度图片找…

大数据技术之DataX

目录 第一章 业务数据同步策略 1.1 全量同步策略 1.2 增量同步策略 1.3 数据同步策略的选择 第2章 DataX介绍 2.1 DataX概述 第3章 DataX架构原理 3.1 DataX的设计理念 3.2 DataX框架设计 3.3 DataX支持的数据源 3.4 DataX运行流程 3.5 DataX调度策略思路 3.6 Data…

数据结构和算法学习记录——二叉树的存储结构二叉树的递归遍历(顺序存储结构、链表存储结构、先序中序后序递归遍历)

目录 顺序存储结构 链表存储结构 二叉树的递归遍历 先序递归遍历 中序递归遍历 后序递归遍历 先序遍历路线图 中序遍历路线图 后序遍历路线图 设想一下二叉树要用什么样的方式来存储&#xff0c;一种是用数组&#xff0c;一种是用链表。 顺序存储结构 用数组&…

IDEA新手入门常用快捷键,方便软件构造

1. Ctrlo快速找方法 2. Alt EnTER 对这个代码快速智能补全trycatch 对这个快速加入要写的接口方法show 3. 使用Ctrl /&#xff0c; 添加行注释 4. 输入psvm 按Tab&#xff0c;自动生成void main 输入souf 按Tab就是System.out.printf() 5. CtrlF12 查看参考代码内部方法…

「她时代」背后的欧拉力量

2018年大热电视剧《北京女子图鉴》&#xff0c;讲述了一群在北京打拼的职业女性&#xff0c;她们背井离乡&#xff0c;被现实包裹&#xff0c;被压力、责任困扰&#xff0c;但依旧用倔强的个性、不屈的进取心和深厚的知识技能努力营造、交织出一片励志的天空&#xff0c;既激昂…

HIT 计统实验2 二进制炸弹(gdb破解版) 拆弹过程

CSAPP 实验2是一个很好玩的实验,网上有很多参考资源写的都很好&#xff0c;本文增加了一些具体细节。 想要我的炸弹可以私信我。 还得看形式语言 &#xff0c; 炸弹6 7 有时间再拆 第1章 实验基本信息 1.1 实验目的 熟练掌握计算机系统的ISA指令系统与寻址方式熟练掌握Linu…

ChatGPT/InstructGPT论文(一)

文章目录一. GPT系列1. in-context learning&#xff08;情景学习&#xff09;二. ChatGPT背景介绍&#xff08;Instruct? Align? 社会化?&#xff09;三. InstructGPT的方法四. InstructGPT工作的主要结论五. 总结六. 参考链接一. GPT系列 基于文本预训练的GPT-1&#xff…

LeetCode 218. 天际线问题

城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度&#xff0c;请返回 由这些建筑物形成的 天际线 。 每个建筑物的几何信息由数组 buildings 表示&#xff0c;其中三元组 buildings[i] [lefti, righti, heighti] 表示&#xf…

76-TCP协议,UDP协议以及区别

TCP协议,UDP协议,SCTP协议一.TCP协议1.什么是TCP协议2.TCP协议的特点3.TCP头部结构4.TCP状态转移5.TCP超时重传二.UDP协议1.什么是UDP协议2.UDP协议的特点三.TCP和UDP的区别一.TCP协议 1.什么是TCP协议 TCP(Transmission Control Protocol)协议即为传输控制协议,是一种面向连…

4.12~(小组成员对话预习)

注意我们这里观察的是XP的kernel32.dll&#xff0c;到win10是有变化的 看了这个函数&#xff0c;似乎是让BasepExeLdrEntry不存在的时候初始化一遍&#xff0c;然后进行对比是否已经加载过这个dll&#xff0c;那么如果加载下一个dll的时候&#xff0c;BasepExeLdrEntry是不是还…

05-vue3的生命周期

文章目录1.生命周期定义钩子函数2.vue3中的生命周期1.普通写法2.setup中写生命周期区别1.生命周期定义 每个 Vue 实例在被创建时都要经过一系列的初始化过程。 例如&#xff1a;从开始创建、初始化数据、编译模板、挂载Dom、数据变化时更新DOM、卸载等一系列过程。 我们称 这一…

【MyBatis】你还不会使用MyBatis逆向工程来提高你的开发效率吗?

文章目录MyBatis逆向工程1、快速入门2、逆向工程配置文件参数详解3、QBC查询MyBatis逆向工程 正向工程&#xff1a;先创建Java实体类&#xff0c;由框架负责根据实体类生成数据库表&#xff08;Hibernate是支持正向工程的&#xff09;逆向工程&#xff1a;先创建数据库表&#…