【BZOJ】【P 254】【tree】【題解】【二分+MST】

1569 ワード

転送ゲート:http://www.lydsy.com/JudgeOnline/problem.php?id=2654
白の辺権を1つの値xに加算すると、最小生成樹における白の辺数の実現可能な最大値g(x)と実行可能最小値f(x)はxの増加とともに減少し、2分の1 xはneed_;[f(x)、g(x)を作ることができる.
コード:
#include<bits/stdc++.h>
#define fst first
#define sec second
using namespace std;
const int maxn=50010;
int ans=0;
struct edge{
	int u,v,w,_w,c;
}edges[int(1e5)+5];int F;
bool cmp(edge a,edge b){return a.w!=b.w?a.w<b.w:(F==1?a.c<b.c:a.c>b.c);}
int fa[maxn];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int n,m,ned;
int cnt[101];
int cnt_dw[101],cnt_up[101];
typedef pair<int,int> par;
map<int,int>tmp,whi;
par Mst(){
	for(int i=1;i<=n;i++)fa[i]=i;int k=0;
	sort(edges+1,edges+1+m,cmp);int res=0,wh=0;
	for(int i=1;i<=m&&k<n-1;i++){
		int u=edges[i].u,v=edges[i].v;
		if(find(v)!=find(u)){
			fa[find(v)]=find(u);k++;
			wh+=edges[i].c==0;res+=edges[i].w;
		}
	}return par(wh,res);
}
int main(){
	scanf("%d%d%d",&n,&m,&ned);
	for(int i=1;i<=m;i++){
		int u,v,w,c;
		scanf("%d%d%d%d",&u,&v,&w,&c);
		u++;v++;
		edges[i].u=u;
		edges[i].v=v;
		edges[i]._w=w;
		edges[i].w=w;
		edges[i].c=c;
		cnt[w]++;
	}int l=-101,r=101;
	while(l<r){
		int mid=(l+r)>>1;
		for(int i=1;i<=m;i++)if(!edges[i].c)edges[i].w=edges[i]._w+mid;
		par up,dw;
		F=1;up=Mst();
		F=0;dw=Mst();
		if(dw.fst<=ned&&ned<=up.fst){
			ans=Mst().sec;
			ans-=ned*mid;break;
		}
		if(ned>up.fst)
			r=mid;
		else l=mid+1;
	}
	cout<<ans<<endl;
	return 0;
}