bzoj2654
二分答案 给白色的边加上边权使刚刚好取到need条
这个二分是靠有右的。。。。
1 #include<bits/stdc++.h> 2 #define clr(a,x) memset(a,x,sizeof(a)) 3 #define rep(i,l,r) for(int i=l;i<r;i++) 4 typedef long long ll; 5 using namespace std; 6 int read() 7 { 8 char c=getchar(); 9 int ans1=0,f=1; 10 while(!isdigit(c)){ 11 if(c=='-') f=-1; 12 c=getchar(); 13 } 14 while(isdigit(c)){ 15 ans1=ans1*10+c-'0'; 16 c=getchar(); 17 } 18 return ans1*f; 19 } 20 struct edge{ 21 int d,v,from,to,p; 22 inline bool operator <(const edge&A)const{ 23 return v<A.v||(v==A.v&&p<A.p); 24 } 25 }; 26 const int maxn=500005,maxm=100005; 27 edge e[maxm]; 28 int f[maxn],n,m,need; 29 int find(int a) 30 { 31 return f[a]==a?f[a]:f[a]=find(f[a]); 32 } 33 int kruskal(int a) 34 { 35 int cnt=0,ans=0; 36 rep(i,0,n) f[i]=i; 37 rep(i,0,m){ 38 if(!e[i].p) e[i].v=e[i].d+a; 39 else e[i].v=e[i].d; 40 } 41 sort(e,e+m); 42 rep(i,0,m){ 43 if(find(e[i].from)!=find(e[i].to)){ 44 f[find(e[i].from)]=find(e[i].to); 45 if(!e[i].p) cnt++; 46 ans+=e[i].v; 47 } 48 } 49 return cnt>=need?ans:-1; 50 } 51 int erfen(int l,int r) 52 { 53 if(l==r) return l; 54 int mid=(l+r+1)>>1; 55 int x=kruskal(mid); 56 if(x==-1) return erfen(l,mid-1); 57 return erfen(mid,r); 58 } 59 int main() 60 { 61 n=read(),m=read(),need=read(); 62 rep(i,0,m){ 63 e[i].from=read(),e[i].to=read(),e[i].d=read(),e[i].p=read(); 64 } 65 int k=erfen(-500,500); 66 printf("%d\n",kruskal(k)-need*k); 67 return 0; 68 }
2654: tree
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 614 Solved: 228
[Submit][Status][Discuss]
Description
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
Input
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行
每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
Output
一行表示所求生成树的边权和。
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
数据规模和约定
0:V<=10
1,2,3:V<=15
0,..,19:V<=50000,E<=100000
所有数据边权为[1,100]中的正整数。