最小生成树,跑了两遍而已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;
}