[ HNOI 2006 ] 公路修建问题
\(\\\)
\(Description\)
一个\(N\)个点\(M\)条边的图,每条边可以选择\(w_i,p_i\)两个边权之一,现求一个生成树上的最大边权最小值,要求这棵生成树上至少有\(K\)条边选择的是\(w_i\)权值。\(Luogu\)上还要以"选了哪些编号的边,每条边选择的是哪种权值"的形式求输出方案。
- \(N\in [1,10^4]\),\(M\in [0,2\times 10^4]\),\(K\in [0,N-1]\),\(w_i,p_i\in [1,3\times 10^4]\)
\(\\\)
\(Solution\)
- 最小生成树变形。先将边按照\(w_i\)排序,按照\(kruskal\)的方式连上\(K\)条边,再按照\(min(w_i,p_i)\)排序,连完剩下的所有边,注意第一遍连上的边要打上标记,避免使用了两次。答案即为所有连过的边中边权最大值,还要注意处理\(K=0\)和\(K=N-1\)的两种情况。
- 关于输出方案,每次记录一下就好,注意第二遍扫描的时候也可能取第一类权值。
\(\\\)
\(Code\)
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 10010
#define M 20010
#define R register
#define gc getchar
using namespace std;
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
int n,m,k,cnt,res,tot;
struct edge{int x,y,w1,w2,num;}e[M];
struct result{int p,x;}ans[N];
inline bool cmp1(edge x,edge y){return x.w1<y.w1;}
inline bool cmp2(edge x,edge y){return min(x.w1,x.w2)<min(y.w1,y.w2);}
inline bool cmp3(result x,result y){return x.p<y.p;}
struct UFS{
int f[N];
UFS(){for(R int i=1;i<N;++i) f[i]=i;}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
inline void merge(int x,int y){f[find(x)]=find(y);}
inline bool judge(int x,int y){return find(x)==find(y);}
}ufs;
int main(){
n=rd(); k=rd(); m=rd()-1;
for(R int i=1;i<=m;++i){
e[i].x=rd(); e[i].y=rd();
e[i].num=i; e[i].w1=rd(); e[i].w2=rd();
}
if(m){
sort(e+1,e+1+m,cmp1);
for(R int i=1;i<=m;++i)
if(!ufs.judge(e[i].x,e[i].y)){
ufs.merge(e[i].x,e[i].y);
ans[++tot].p=e[i].num; ans[tot].x=1;
res=max(res,e[i].w1); if((++cnt)==k) break;
}
}
if(cnt<n-1){
sort(e+1,e+1+m,cmp2);
for(R int i=1;i<=m;++i)
if(!ufs.judge(e[i].x,e[i].y)){
ufs.merge(e[i].x,e[i].y);
ans[++tot].p=e[i].num;
if(e[i].w1<e[i].w2){ans[tot].x=1;res=max(res,e[i].w1);}
else{ans[tot].x=2;res=max(res,e[i].w2);}
}
}
printf("%d\n",res);
sort(ans+1,ans+1+tot,cmp3);
for(R int i=1;i<=tot;++i) printf("%d %d\n",ans[i].p,ans[i].x);
return 0;
}