首页 > 其他分享 >复杂最短路做题笔记

复杂最短路做题笔记

时间:2023-07-18 13:45:24浏览次数:49  
标签:连通 复杂 int 短路 tr 最小 笔记 maxn id

1 . CF609E Minimum spanning tree for each edge

luogu传送门

CodeForces传送门

题意

给你 \(n\) 个点,\(m\) 条边,对于编号位i的边求出必须包含i的最小生成树权值和。

很好理解,不做赘述。

题解

前置芝士:Kruskal算法求最小生成树,ST表倍增。

首先,我们不考虑每条边的限制,先将整张图的最小生成树求出,连边建树并求权值和。

现在加入限制。

对于第 \(i\) 条边,如果 \(i\) 在最小生成树上,直接输出权值和即可。

不在的情况值得讨论。

假设我们直接在树上加入了第 \(i\) 条边,设 \(i\) 连接 \(u\) 和 \(v\),那么我们在加入的同时需要断掉原最小生成树上 \(u\),\(v\) 路径上的一条边,否则就不是一棵树了。

显而易见,设最小生成树权值和为 \(all\),\(i\) 的边权为 \(w\) ,短边边权为 \(w'\)

则有 \(ans=all+w-w'\)

所以显然需要断掉 \(u\),\(v\) 路径上边权最大的边。

求出这条边显然可以使用倍增。

所以整体思路就很清楚了,先建出最小生成树,再考虑每一条边,若在树上直接输出权值和,否则求个倍增最大值。结束了。

code

//writer:Oier_szc

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n,m;
struct node
{
	int u,v,w,id;
	bool operator<(const node &W) const
	{
		return w<W.w;
	}
}e[N];
int fa[N];
int find(int u)
{
	if(fa[u]==u) return fa[u];
	else return fa[u]=find(fa[u]);
}
void merge(int a,int b)
{
	fa[a]=b;
}
int head[N],ne[N<<1],to[N<<1],w[N<<1],tot=0;
void add(int u,int v,int W)
{
	to[++tot]=v;
	w[tot]=W;
	ne[tot]=head[u];
	head[u]=tot;
}
bool in[N];
int ANS=0,p[20][N],deep[N],st[20][N];
void dfs(int u,int fa)
{
	p[0][u]=fa;
	deep[u]=deep[fa]+1;
	for(int i=head[u];i;i=ne[i])
	{
		if(to[i]==fa) continue;
		st[0][to[i]]=w[i];
		dfs(to[i],u);
	}
}
void init()
{
	for(int i=1;i<20;++i)
	{
		for(int j=1;j<=n;++j)
		{
			if(p[i-1][j]!=-1) 
			{
				p[i][j]=p[i-1][p[i-1][j]];
				st[i][j]=max(st[i-1][j],st[i-1][p[i-1][j]]);
			}
		}
	}
}
int LCA(int a,int b)
{
	if(deep[b]>deep[a]) swap(a,b);
	int maxn=0;
	for(int i=19;i>=0;--i)
	{
		if(p[i][a]!=-1&&deep[p[i][a]]>=deep[b])
		{
			maxn=max(maxn,st[i][a]);
			a=p[i][a];
		}
	}
	if(a==b) return maxn;
	for(int i=19;i>=0;--i)
	{
		if(p[i][a]!=-1&&p[i][a]!=p[i][b])
		{
			maxn=max(maxn,max(st[i][a],st[i][b]));
			a=p[i][a];
			b=p[i][b];
		}
	}
	return max(maxn,max(st[0][a],st[0][b]));
}
int ans[N];
signed main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=m;++i)
	{
		scanf("%lld%lld%lld",&e[i].u,&e[i].v,&e[i].w);
		e[i].id=i;
	}
	sort(e+1,e+1+m);
	int fu,fv;
	for(int i=1;i<=n;++i) fa[i]=i;
	for(int i=1;i<=m;++i)
	{
		fu=find(e[i].u);
		fv=find(e[i].v);
		if(fu==fv) continue;
		merge(fu,fv);
		add(e[i].u,e[i].v,e[i].w);
		add(e[i].v,e[i].u,e[i].w);
		in[e[i].id]=true;
		ANS+=e[i].w;
	}
	dfs(1,-1);
	init();
	for(int i=1;i<=m;++i)
	{
		if(in[e[i].id]) ans[e[i].id]=ANS;
		else
		{
			ans[e[i].id]=ANS+e[i].w-LCA(e[i].u,e[i].v);
		}
	}
	for(int i=1;i<=m;++i)
	{
		printf("%lld\n",ans[i]);
	}
	return 0;
}

2 . CF888G Xor-MST

前置芝士:Boruvka算法,01Trie

luogu传送门

CodeForces传送门

题意

给你一张最多有 \(2 \times 10^5\) 个点的完全图,两两之间边权为两点点权的异或,让你求最小生成树。

题解

又神又难写的题。

对于完全图的最小生成树,显然Prim和Kruskal都难以胜任,这道题涉及到了一个全新的算法叫Boruvka算法。

Boruvka算法流程

其实和Kruskal很类似。首先还是并查集。

先将所有单个点的祖先调整成自己。然后开始合并连通块。

对于每一次合并,我们找到每一个连通块的点连到其它连通块的最小的一条边,然后将两个连通块合并。有一小点分治的味道。

当然,这里要注意是,可能会出现重边的情况。例如连通块A连出去到了连通块B,但连通块B连出去的最小边正好是集合A,不判重会算两次,会出问题。

对于复杂度,首先看每一次合并,显然是\(O(E)\);然后看合并次数,可以发现每次合并连通块数量至少减半,所以最多合并\(O(log\ N)\)次,总复杂度自然是\(O(E\ log\ N)\)。

如果想深入学习该算法可以右转oi-wiki

回到题目x1

直接套这个算法怎么行,边都到 \(10\) 的 \(10\) 次方级别了。

考虑优化找到最小边的过程。

考虑枚举每一个点。对于一个点,如果想找到与其异或起来的最小值,有一个很常用的套路。那就是01Trie。

如何找呢?再看一道模板题。

最长异或路径

不妨将每一个数变成二进制串,从高往低位插入字典树。

考虑访问。根据贪心的思想,对于一个数 \(a\) 的二进制表示,显然在访问的过程中要使得最高位尽可能与 \(a\) 不同,因为最高位比下面几位都大,显然这样才能将异或结果最大化。

所以问题的解显而易见,在访问时从最高位开始尽可能的与 \(a\) 不同,最后返回值即可。

回到题目x2

同理,我们就可以通过01Trie求出每个点连到其它连通块的最小值。只要将尽可能相反变成尽可能相同,即可将一次合并复杂度变为 \(O(N\ log\ V)\) 。

但是具体如何套进算法还有一堆细节。

显然,01Trie上访问时不能访问到当前连通块的元素。为解决,不妨将Trie想成一个普通的树,我们设 \(l[i]\) 和 \(r[i]\) ,表示 \(i\) 号点子树内所有元素所在连通块编号的最小值和最大值,那么当 \(l[to]=r[to]=id\)
(\(id\) 表示现在查询的元素所在的连通块)时,就不能进入子树 \(to\) 中访问。

还有一点就是每一轮Boruvka中的合并后要将整个Trie dfs一遍,更新01Trie内所有点的 \(l[i]\) 和 \(r[i]\),这相对好办。

将所有细节整合起来,耐心码一下代码,你就能A一道上位紫了!

code

//writer:Oier_szc

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n;
long long ans=0;
int a[N];
int tr[N*32][2],ID[N*32],idx=0;
int l[N*32],r[N*32];
int fa[N];
inline int find(int u)
{
	if(fa[u]==u) return fa[u];
	else return fa[u]=find(fa[u]);
}
inline void insert(int x,int id)
{
	int u=0;
	for(register int i=29;i>=0;--i)
	{
		int to=(x>>i)&1;
		if(!tr[u][to]) tr[u][to]=++idx;
		u=tr[u][to];
	}
	ID[u]=id;
}
inline void dfs(int u)
{
	if(ID[u])
	{
		l[u]=r[u]=find(ID[u]);
		return;
	}
	l[u]=0x3f3f3f3f;
	r[u]=0;
	if(tr[u][0])
	{
		dfs(tr[u][0]);
		l[u]=min(l[u],l[tr[u][0]]);
		r[u]=max(r[u],r[tr[u][0]]);
	}
	if(tr[u][1])
	{
		dfs(tr[u][1]);
		l[u]=min(l[u],l[tr[u][1]]);
		r[u]=max(r[u],r[tr[u][1]]);
	}
}
inline pair<int,int> query(int x,int id)
{
	int u=0,res=0;
	for(register int i=29;i>=0;--i)
	{
		int to=(x>>i)&1;
		if(tr[u][to]&&!(l[tr[u][to]]==r[tr[u][to]]&&l[tr[u][to]]==id))
		{
			res=(res<<1)+to;
			u=tr[u][to];
		}
		else if(tr[u][!to]&&!(l[tr[u][!to]]==r[tr[u][!to]]&&l[tr[u][!to]]==id))
		{
			res=(res<<1)+!to;
			u=tr[u][!to];
		}
		else break;
	}
	return make_pair(res,ID[u]);
}
int best[N],bestid[N];
signed main()
{
	scanf("%d",&n);
	for(register int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
	} 
	sort(a+1,a+1+n);
	n=unique(a+1,a+1+n)-a-1;
	for(int i=1;i<=n;++i) 
	{
		fa[i]=i;
		insert(a[i],i);
	}
	int cnt=0; 
	while(cnt<n-1)
	{
		for(register int i=1;i<=n;++i)
		{
			best[i]=0x3f3f3f3f;
		}
		dfs(0);
		pair<int,int> qwq; 
		int fu,fv;
		for(register int i=1;i<=n;++i)
		{
			fu=find(i);
			qwq=query(a[i],fu);
			fv=find(qwq.second);
			if((a[i]^qwq.first)<best[fu])
			{
				best[fu]=(a[i]^qwq.first);
				bestid[fu]=fv;
			}
			if((a[i]^qwq.first)<best[fv])
			{
				best[fv]=(a[i]^qwq.first);
				bestid[fv]=fu;
			}
		}
		for(register int i=1;i<=n;++i)
		{
			if(fa[i]!=i) continue;
			if(best[i]<0x3f3f3f3f&&bestid[i]!=0)
			{
				if(bestid[bestid[i]]==i) bestid[bestid[i]]=0;//判重边
				fa[i]=bestid[i];
				ans+=best[i];
				++cnt;
			}
		}
	}
	printf("%lld",ans);
	return 0;
}

标签:连通,复杂,int,短路,tr,最小,笔记,maxn,id
From: https://www.cnblogs.com/StevenZC/p/17559803.html

相关文章

  • win10小狼毫配置实操笔记
    下载安装进入官方网站下载最新版小狼毫,安装后选择朙(明)月拼音。在配置前阅读官方文档有关用户文件夹和共享文件夹的介绍。default.yaml用来调试全局方案,定制该文件后切换其他比如五笔、双拼等方案时,其定制内容依旧适用。weasel.yaml用来修改rime的常规设置,定制外观。symbol......
  • [论文笔记] Line-CNN: End-to-End Traffic Line Detection With Line Proposal Unit
    IEEETITS2019YangJianlastupdate:2023/07/17简介作者受Faster-RCNN启发,提出Line-CNN,提出了一种新颖的车道线Anchor的表示方法,解决了车道线检测中表征的难点,实现了端到端的车道线检测.车道线是一条曲线,所以无法使用常规检测中矩形bbox作为Anchor,为了用Anchor来......
  • MIT6.S081学习笔记--lec 1
    引言操作系统的目标abstractH/W抽象化硬件multiplex多路复用isolation隔离性sharing共享(进程通信,数据共享)security/accesscontrol安全性/权限控制performance性能/内核开销rangeofapplications多应用场景操作系统概览操作系统应该提供的功能:1.多进程支......
  • TransE 学习笔记
    目录TransEWhatisTransE?MotivationTransE算法过程输入参数训练过程实验小结TransEpaper:TranslatingEmbeddingsforModelingMulti-relationalDataTransE是由AntoineBordes发表于2013年的NIPS(现NeurIPS)上的工作,众所周知这篇文章是知识图谱表示学习的开山之作,......
  • 数据结构练习笔记——删除单链表中相同元素
    删除单链表中相同元素【问题描述】单链表中存放了若干整数,请删除相同整数。【输入形式】单链表【输出形式】删除相同整数后的单链表【样例输入】11123【样例输出】123【样例说明】递增的形式输入数据,允许相同元素#include<stdlib.h>#include<iostream>usingname......
  • 使用 JavaScript 脚本来进行复杂的查询改写
    有这么一个需求:网关里怎样对跨集群搜索进行支持的呢?我想实现:输入的搜索请求是lp:9200/index1/_search这个索引在3个集群上,需要跨集群检索,也就是网关能否改成lp:9200/cluster01:index1,cluster02,index1,cluster03:index1/_search呢?索引有一百多个,名称不一定是app,还......
  • SpringBoot官方笔记4Web
    Mostwebapplicationsusethe spring-boot-starter-web moduletogetupandrunningquickly.Youcanalsochoosetobuildreactivewebapplicationsbyusingthe spring-boot-starter-webflux module.ServletWebApplicationsSpringWebMVCFrameworkimportja......
  • SpringBoot官方笔记3核心
    SpringApplicationBydefault, INFO loggingmessagesareshown,includingsomerelevantstartupdetails,suchastheuserthatlaunchedtheapplication.LazyInitializationWhenlazyinitializationisenabled,beansarecreatedastheyareneededratherth......
  • SpringBoot官方笔记7IO
    CachingSpringBootauto-configuresthecacheinfrastructureaslongascachingsupportisenabledbyusingthe @EnableCaching annotation.importorg.springframework.cache.annotation.Cacheable;importorg.springframework.stereotype.Component;@Component......
  • SpringBoot官方笔记6消息
    TheSpringFrameworkprovidesextensivesupportforintegratingwithmessagingsystems,fromsimplifieduseoftheJMSAPIusing JmsTemplate toacompleteinfrastructuretoreceivemessagesasynchronously.SpringAMQPprovidesasimilarfeaturesetforth......