bzoj2654: tree
二分答案。不断的增加白色边的值,让白色边更多的出现在MST上。调了挺久,因为ans没有初始化一个值,因此当rep(i,m)没有运行是ans是随机的。注意。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) int read(){ int x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } const int nmax=50005; const int maxn=100005; const int inf=0x7f7f7f7f; struct edge{ int from,to,dist,op; bool operator<(const edge &rhs) const{ return dist<rhs.dist||(dist==rhs.dist&&op<rhs.op);} }; edge edges[maxn]; int fa[nmax],n,m,need; int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); } int check(int x){ rep(i,n) fa[i]=i; int ans=0,cnt=0; rep(i,m) if(!edges[i].op) edges[i].dist+=x; sort(edges+1,edges+m+1); rep(i,m){ int ta=find(edges[i].from);int tb=find(edges[i].to); if(ta!=tb) { fa[ta]=tb;ans+=edges[i].dist; if(!edges[i].op) cnt++; } } rep(i,m) if(!edges[i].op) edges[i].dist-=x; return cnt>=need?ans:-1; } void work(){ int ans,l=-300,r=300; while(l<=r){ int mid=(l+r)>>1; int tmp=check(mid); if(tmp!=-1) { ans=tmp-need*mid;l=mid+1; }else r=mid-1; } printf("%d\n",ans); } int main(){ n=read(),m=read(),need=read(); rep(i,m){ edge &oo=edges[i]; oo.from=read()+1,oo.to=read()+1,oo.dist=read(),oo.op=read(); } work();return 0; }
2654: tree
Submit: 1343 Solved: 495
[Submit][Status][Discuss]
Description
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
Input
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
Output
一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
Sample Input
2 2 1
0 1 1 1
0 1 2 0
0 1 1 1
0 1 2 0
Sample Output
2
HINT
原数据出错,现已更新 by liutian,但未重测---2016.6.24
Source