BZOJ1196&&洛谷P2323 [HNOI2006]公路修建问题

最小生成树,跑了两遍而已233

第一遍用一级公路跑最小生成树,凑够k条边就跳出,然后把剩下的边,按二级公路跑最小生成树,然后记录max就好了

BZOJ没有让输出方案,贡献了一发OLE

代码

//By AcerMo
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=200500;
int n,m,l;
int fa[M],siz[M],chos[M];
struct edge{int fr,to,c1,c2,id;}e[M];
inline bool cmp1(edge a,edge b){return a.c1<b.c1;}
inline bool cmp2(edge a,edge b){return a.c2<b.c2;}
inline int read()
{
	int x=0;char ch=getchar();
	while (ch>'9'||ch<'0') ch=getchar();
	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x;	
} 
inline int find(int x)
{
	if (x!=fa[x]) return fa[x]=find(fa[x]);
	return x;
}
inline void unionn(int a,int b)
{
	if (siz[a]<=siz[b]) siz[b]+=siz[a],fa[a]=b;
	else siz[a]+=siz[b],fa[b]=a;
	return ;
}
inline void constt()
{
	for (int i=1;i<=n;i++) siz[i]=1,fa[i]=i;
	return ;
}
signed main()
{
	n=read();l=read();m=read();constt();
	for (int i=1;i<m;i++) 
	e[i].fr=read(),e[i].to=read(),e[i].c1=read(),e[i].c2=read(),e[i].id=i;
	sort(e+1,e+m,cmp1);int poi=0,tot=0,maxa=0;
	for (int i=1;i<m;i++)
	{
		int r1=find(e[i].fr);
		int r2=find(e[i].to);
		if (r1!=r2) 
		{
			tot++;maxa=e[i].c1;unionn(r1,r2);chos[e[i].id]=1;
			if (tot==l){poi=i;break;}
		}
	}
	sort(e+poi+1,e+m,cmp2);
	for (int i=poi+1;i<m;i++)
	{
		int r1=find(e[i].fr);
		int r2=find(e[i].to);
		if (r1!=r2)
		{
			unionn(r1,r2);tot++;maxa=max(maxa,e[i].c2);chos[e[i].id]=2;
			if (tot==n-1) break;
		} 
	}
	cout<<maxa<<endl;
	for (int i=1;i<m;i++)
	if (chos[i])
	printf("%d %d\n",i,chos[i]);
	return 0;
}

 

    原文作者:道路修建问题
    原文地址: https://blog.csdn.net/ACerAndAKer/article/details/82260818
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞