ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[BJWC2010]严格次小生成树

2022-07-12 21:33:34  阅读:173  来源: 互联网

标签:maxn int s1 生成 严格 Sec m2 Maxn BJWC2010


做题时间:2021.8.8

\(【题目描述】\)

给你一张 \(N(1\leq N\leq 10^5)\) 个点 \(M(1\leq M\leq 3\times 10^5)\) 条边的无向图,求出这张图中严格次小生成树。

\(【输入格式】\)

第一行两个整数 \(N,M\)
接下来 \(M\) 行每行三个整数 \(u,v,w\) 表示图上一条边

\(【输出格式】\)

一行一个数表示答案

\(【考点】\)

最小生成树、倍增DP

\(【做法】\)

次小生成树与最小生成树有关,可以考虑先求出最小生成树,然后遍历不在最小生成树上的每一条边,加入树中,并删除所形成的环中的一条边使其重新构成一棵新树,删除的这条边必定是环中最大或次大的(当最大值=加入的边的边权时,应当删除次大边),因此问题转化为:求最小生成树+枚举边 \((u,v)\) + 倍增求 \((u,lca)\) 和 \((v,lca)\) 路径上的最大值和次大值。

最后一步可以像求LCA一样分成三个部分:

  1. 求出 \(m_{u,i}\) 与 \(s_{u,i}\) 分别表示 \(u\) 到其 \(2^i\) 级祖先的路径上的最大值以及次大值。具体而言,定义 \(k\) 表示 \(u\) 的 \(2^{i-1}\) 级祖先,若 \(m_{u,i-1}>m_{k,i-1}\) ,则有 \(m_{u,i}=\max(m_{k,i-1},s_{u,i-1})\) ,若 \(m_{u,i-1}<m_{k,i-1}\) ,则有 \(m_{u,i}=\max(m_{u,i-1},s_{k,i-1})\) ,若 \(m_{u,i-1}=m_{k,i-1}\) ,则有 \(m_{u,i}=\max(s_{u,i-1},s_{k,i-1})\)

  2. 将 \(u,v\) 中深度较大的先上跳至与 \(v\) 深度相同处(设它是 \(u\) ),上跳过程中求最大值与次大值与1同理。

  3. 将 \(u,v\) 一起上跳至lca的儿子处。

注意:输入数据中可能会有自环,影响答案,要进行判断;

#include<cstdio>
#include<iomanip>
#include<algorithm>
using namespace std;
const int N=1e5+50,M=3e5+50;
typedef long long ll;
struct edge{
	int to,nxt,val;
}a[N<<1];
int head[N],tot;
struct G{
	int u,v,w;
}g[M];
int fa[N],f[N][30],dep[N];
int maxn[N][30],Sec_maxn[N][30];
bool vis[M];
int n,m;
inline ll Min(ll a,ll b){return a<b?a:b;}
inline ll Max(ll a,ll b){return a>b?a:b;}
inline ll Swap(int &x,int &y){int t=x;x=y;y=t;}

#define m1 maxn[x][i-1]
#define m2 maxn[f[x][i-1]][i-1]
#define m3 maxn[x][i]

#define s1 Sec_maxn[x][i-1]
#define s2 Sec_maxn[f[x][i-1]][i-1]
#define s3 Sec_maxn[x][i]


void Work1(int x,int fa,int pre)
{
	dep[x]=dep[fa]+1,f[x][0]=fa;
	maxn[x][0]=pre;
	for(int i=1;i<=20;i++){
		f[x][i]=f[f[x][i-1]][i-1];
		m3=Max(m1,m2);
		
		//分三种情况 
		if(m1>m2) s3=Max(m2,s1);//m1>m2>s2 ,只有m2和s1有机会成为次大值 
		if(m1==m2) s3=Max(s1,s2);//m1==m2>s1,s2 ,只有m2和s1有机会成为次大值 
		if(m1<m2) s3=Max(m1,s2);//m2>m1>s1 ,只有m1和s2有机会成为次大值 
	}
}
void Work2(int x,int i,int &Maxn,int &Sec)
{
	//分三种情况,同上 
	if(Maxn>m3) Sec=Max(m3,Sec);
	if(Maxn==m3) Sec=Max(s3,Sec);
	if(Maxn<m3) Sec=Max(Maxn,s3);
	Maxn=Max(m3,Maxn);
}
ll Find(int x,int y,int z)//上跳求最大值和次大值 
{
	int Maxn=0,Sec=0;
	if(dep[x]<dep[y]) Swap(x,y);
	
	for(int i=20;i>=0;i--){
		if(dep[f[x][i]]>=dep[y]){
			Work2(x,i,Maxn,Sec);//求出x到x的2^i级祖先路径上的最大值和次大值 
			x=f[x][i];
		}
	}
	if(x==y){
		if(Maxn==z) return Sec;
		return Maxn;
	}
	for(int i=20;i>=0;i--){
		if(f[x][i]!=f[y][i]){
			Work2(x,i,Maxn,Sec);//求出x到x的2^i级祖先路径上的最大值和次大值 
			Work2(y,i,Maxn,Sec);//求出y到y的2^i级祖先路径上的最大值和次大值 
			x=f[x][i],y=f[y][i];
		}
	}
	Work2(x,0,Maxn,Sec);//最后x到lca和y到lca 
	Work2(y,0,Maxn,Sec);
	if(Maxn==z) return Sec;
	return Maxn;
}

void DFS(int u,int fa,int pre)
{
	Work1(u,fa,pre);
	for(int i=head[u];i;i=a[i].nxt){
		int v=a[i].to;
		if(v!=fa) DFS(v,u,a[i].val);
	}
}

namespace MST{//求最小生成树 
	bool cmp(G a,G b){return a.w<b.w;}
	void add(int u,int v,int w)
	{
		tot++;
		a[tot].to=v;
		a[tot].val=w;
		a[tot].nxt=head[u];
		head[u]=tot;
	}
	int Find(int x)
	{
		if(x==fa[x]) return x;
		return fa[x]=Find(fa[x]);
	}
	bool Merge(int x,int y)
	{
		int X=Find(x),Y=Find(y);
		if(X==Y) return false;
		fa[X]=Y;return true;
	}
	ll Kruskal()
	{
		ll ans=0;
		int cnt=0;
		sort(g+1,g+1+m,cmp);
		for(int i=1;i<=m;i++){
			if(Merge(g[i].u,g[i].v)){
				cnt++;
				add(g[i].u,g[i].v,g[i].w);
				add(g[i].v,g[i].u,g[i].w);
				vis[i]=true;
				ans+=(ll)g[i].w;
			}
			if(cnt==n-1) break;
		}
		return ans;
	}
}
using namespace MST;
inline int Read()
{
	int x=0;
	char ch=getchar();
	while(ch>'9'||ch<'0') ch=getchar();
	while(ch>='0'&&ch<='9'){
		x=(x<<1)+(x<<3)+ch-48;
		ch=getchar();
	}
	return x;
}
int main()
{
	n=Read(),m=Read();
	for(int i=1;i<=n;i++) fa[i]=i;//并查集初始化 
	int root=0;
	for(int i=1;i<=m;i++){
		g[i].u=Read(),g[i].v=Read(),g[i].w=Read();
		root=g[i].u;
	}
	ll ans=Kruskal(),tmp=2147483645;
	DFS(root,0,0);
	for(int i=1;i<=m;i++){
		if(!vis[i]&&g[i].u!=g[i].v){//若这条边不在MST中且不是自环 
			tmp=Min(tmp,g[i].w-Find(g[i].u,g[i].v,g[i].w));
		}
	}
	printf("%lld\n",ans+tmp);
	return 0;
}

标签:maxn,int,s1,生成,严格,Sec,m2,Maxn,BJWC2010
来源: https://www.cnblogs.com/Unlimited-Chan/p/16471846.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有