首页 > 其他分享 >【题解 P4180】严格次小生成树

【题解 P4180】严格次小生成树

时间:2023-08-28 15:26:57浏览次数:42  
标签:val 题解 t1 long 生成 权值 P4180 val1 else

[BJWC2010] 严格次小生成树

题目描述

小 C 最近学了很多最小生成树的算法,Prim 算法、Kruskal 算法、消圈算法等等。正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是 \(E_M\),严格次小生成树选择的边集是 \(E_S\),那么需要满足:(\(value(e)\) 表示边 \(e\) 的权值) \(\sum_{e \in E_M}value(e)<\sum_{e \in E_S}value(e)\)。

这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

输入格式

第一行包含两个整数 \(N\) 和 \(M\),表示无向图的点数与边数。

接下来 \(M\) 行,每行 \(3\) 个数 \(x,y,z\) 表示,点 \(x\) 和点 \(y\) 之间有一条边,边的权值为 \(z\)。

输出格式

包含一行,仅一个数,表示严格次小生成树的边权和。

样例 #1

样例输入 #1

5 6
1 2 1 
1 3 2 
2 4 3 
3 5 4 
3 4 3 
4 5 6

样例输出 #1

11

提示

数据中无向图不保证无自环

对于 \(50\%\) 的数据, \(N\le 2000\),\(M\le 3000\)。

对于 \(80\%\) 的数据, \(N\le 5\times 10^4\),\(M\le 10^5\)。

对于 \(100\%\) 的数据, \(N\le 10^5\),\(M\le 3\times10^5\),边权 \(\in [0,10^9]\),数据保证必定存在严格次小生成树。

原题地址

解法

题意还是很容易理解的,求严格最小的生成树。
很经典的一个想法,跑 \(kruskal\) 后最小生成树维护两点之间路径上最大的权值,枚举每条未放进最小生成树的边,拿最小生成树权值和减去路径最大权值再加上这条边的权值即可。
结果打完发现连样例都没过。
观察样例后发现,路径上存在与这条边权值相同的边,而题目是严格最小。
所以, \(LCA\) 时还要维护严格次小的边。
当路径上最大权值与此边权值相等时,就用次小权值来。
证明显然,只可能改掉一条边,因为原来是最小生成树,每次改边都会增大权值,改两边不如改一边优。
删掉最大或次大边,可以使剩下选的边权值和最小,从而使加上枚举的边后权值和最小。

代码

#include<bits/stdc++.h>
using namespace std;
struct datay
{
	long long x,y,z;
}l[300005];
long long n,m,d[300005],f[300005][21],deep[300005],t[300005][21],val=0,t1[300005][21],val1;
bool v[300005];
vector<long long> a[300005],r[300005];
long long dijah(long long x)
{
	if(d[x]!=x)d[x]=dijah(d[x]);
	return d[x];
}
void dfs(long long x,long long y)
{
	deep[x]=deep[y]+1;
	f[x][0]=y;
	for(int i=0;i<a[x].size();i++)
	{
		if(a[x][i]==y)continue;
		t[a[x][i]][0]=r[x][i];
		dfs(a[x][i],x);
	}
	return;
}
bool cmp(datay q,datay w)
{
	return q.z<w.z;
}
long long LCA(long long x,long long y)
{
	val=0;
	val1=0;
	if(deep[x]<deep[y])swap(x,y);
	for(int i=20;i>=0;i--)
	{
		if(deep[f[x][i]]>=deep[y])
		{
			if(val1<=t1[x][i])
			{
				if(t1[x][i]>val)val1=t1[x][i];
				else if(t[x][i]>val)val1=val;
				else if(t[x][i]!=val)val1=t[x][i];
				else val1=max(t1[x][i],val1);
			}
			else if(t1[x][i]<val1&&t[x][i]>=val1)val1=t[x][i]==val?val1:min(val,t[x][0]);
			val=max(val,t[x][i]),x=f[x][i];
		}
	} 
	if(x==y)return x;
	for(int i=20;i>=0;i--)
	{
		if(f[x][i]!=f[y][i])
		{
			if(val1<=t1[x][i])
			{
				if(t1[x][i]>val)val1=t1[x][i];
				else if(t[x][i]>val)val1=val;
				else if(t[x][i]!=val)val1=t[x][i];
				else val1=max(t1[x][i],val1);
			}
			else if(t1[x][i]<val1&&t[x][i]>=val1)val1=t[x][i]==val?val1:min(val,t[x][0]);
			val=max(val,t[x][i]);
			if(val1<=t1[y][i])
			{
				if(t1[y][i]>val)val1=t1[y][i];
				else if(t[y][i]>val)val1=val;
				else if(t[y][i]!=val)val1=t[y][i];
				else val1=max(t1[y][i],val1);
			}
			else if(t1[y][i]<val1&&t[y][i]>=val1)val1=t[y][0]==val?val1:min(val,t[y][0]);
			val=max(val,t[y][i]);
			x=f[x][i];
			y=f[y][i];
		}
	}
	if(val>t[x][0])val1=t[x][0];
	val=max(val,t[x][0]);
	if(val>t[y][0])val1=t[y][0];
	val=max(val,t[y][0]);
	return f[x][0];
}
int main()
{
	long long x,y,s=0,minn=1e15+5;
	memset(v,false,sizeof(v));
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld%lld",&l[i].x,&l[i].y,&l[i].z);
	}
	for(int i=1;i<=m;i++)d[i]=i;
	sort(l+1,l+m+1,cmp);
	for(int i=1;i<=m;i++)
	{
		x=dijah(l[i].x),y=dijah(l[i].y);
		if(x!=y)
		{
			a[l[i].x].push_back(l[i].y);
			a[l[i].y].push_back(l[i].x);
			r[l[i].x].push_back(l[i].z);
			r[l[i].y].push_back(l[i].z);
			d[y]=x;
			s+=l[i].z;
			v[i]=true;
		}
	}
	dfs(1,0);
	for(int i=1;i<=20;i++)
	{
		for(int j=1;j<=n;j++)
		{
			f[j][i]=f[f[j][i-1]][i-1];
			t[j][i]=max(t[j][i-1],t[f[j][i-1]][i-1]);
			if(t[j][i-1]!=t[f[j][i-1]][i-1])t1[j][i]=min(t[j][i-1],t[f[j][i-1]][i-1]);
			else
			{
				t1[j][i]=max(t1[j][i-1],t1[f[j][i-1]][i-1]);
			}
		}
	}
	for(int i=1;i<=m;i++)
	{
		if(v[i]||l[i].x==l[i].y)continue;
		LCA(l[i].x,l[i].y);
		if(val!=l[i].z)minn=min(minn,s-val+l[i].z);
		if(val1!=l[i].z)minn=min(minn,s-val1+l[i].z);
	}
	printf("%lld",minn);
	







  return 0;
}

标签:val,题解,t1,long,生成,权值,P4180,val1,else
From: https://www.cnblogs.com/dijah/p/17662346.html

相关文章

  • [struts2]配置dispatcher INCLUDE和Forward可能问题解决
    Struts2.1.6GA不支持<dispatcher>FORWARD</dispatcher>和<dispatcher>INCLUDE</dispatcher>你要是和URLRewrite过滤器一起工作会报错。目前最新版本GeneralAvailability(GA)Releases-ReadyforPrimeTime!Struts2.1.8("bestavailable")Struts2.0.14(&qu......
  • 效果器——反向生成匹配响度
    反向就是从尾到头播放生成的时候,光标一定要放在最前面就在最前面生成了一个噪音匹配响度把音乐丢进去,运行声音就会平滑一点听起来更顺耳......
  • JDK1.5在WIN7中显示时间不正确的问题解决
    最近发现一些新的windows操作系统中,JDK显示的时区不是正确的GMT+08的,而是默认的格林威治时间原以为是系统时区设置不对,但发现系统时间正确,时区也正确,就是JDK的不正确网上很多方法都是手动改tomcat设置,或者在代码中写死时区,这种做法都是治标不治本的于是继续查找根本所在后来几经比......
  • C# 验证码的简单生成,登录实现校验验证码
    登录实现校验验证码1、思路:首先写一个生成验证码的接口,接口传出就是验证码的唯一id和验证码图片的base64,把验证码的id当做缓存的key,再把生成的验证码code当做值存到缓存中。2、登录:输入用户名、密码、验证码唯一id和用户输入的验证码值。用验证码唯一id获取到缓存中的验证码值,......
  • 关于win7图片查看很慢的问题解决
     找了很久都没找到解决方案,奇怪为什么网上没有人跟我遇到同样的问题?我对win7自带的图片和传真查看器一直是相当的不满意了,原来xp自带的版本,什么图片格式都能看可是win7里面,gif看不了(静态的),emf和wmf这种矢量图文件更是干脆都不支持最郁闷的是查看普通的jpg都很慢很慢。。。已经到......
  • P5629 【AFOI-19】区间与除法 题解
    P5629【AFOI-19】区间与除法题解由于题目中的运算是除法,所以对于一个数字\(x\),最多运算次数不会超过\(\lceil\log_{d}x\rceil\)就会变成\(0\)。然后我们就可以在\(O(n\logC)\)的时间复杂度内算出来每一个数字能被哪些原数消灭。这样处理询问仍然棘手,接下来有一个性质:......
  • SpringMVC3的ResponseBody返回字符串乱码问题解决
    SpringMVC的@ResponseBody注解可以将请求方法返回的对象直接转换成JSON对象,但是当返回值是String的时候,中文会乱码 原因是因为其中字符串转换和对象转换用的是两个转换器,而String的转换器中固定了转换编码为"ISO-8859-1" 网上也很多种解决方法,有通过配置Bean编码的,也有自己重写转......
  • CSS的htc文件对于脚本生成的html无效的处理方法
    最近用PIE.htc开发CSS3的网页时,发现用到PIE.htc的CSS效果对于用脚本生成的html代码都无效的情况众所周知htc是IE针对CSS开放的一种特殊实现方式htc的实现是在页面载入完成后开始的,类似于js的window.onload(),它并不是像CSS语言那样,成为浏览器原生的语言,所以当页面内容使用js生成时,其......
  • 数位dp部分题解
    前言最近学了一种新的数位dp的状态表示,打算应用到以前做过的数位dp的题目。如果我们对数$N$进行数位dp,以前的状态定义$f(i,j)$表示所有数位大小为$i$且最高位是数字$j$的数的个数,如果还有其他约束条件那么再补充相应的状态即可。而新的状态定义则是$f(i,1)$和$f(i,0)$,其中$f(......
  • 销售基因链 题解
    销售基因链题目大意给定\(n\)个字符串,长度总和为\(m\),进行\(q\)次询问,每次询问给定两个字符串\(p,s\),问所有的字符串中以\(p\)为前缀且以\(s\)为后缀的有多少个。思路分析分享一个船新的答辩做法。(目前是最劣解)考虑哈希,对每个给定的字符串前后各做一遍哈希,将所有的......