【BZOJ 2654】 MST
2654: tree
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 0Sample Output
2HINT
原数据出错,现已更新 by liutian,但未重测---2016.6.24
Source
【分析】
嗯?我想不到的题。。如果不断给所有白色边加上同一个值,跑MST(边权相同先选白色边),那么选取的白色边的数量显然是不升的,就这样,最后减掉need*add就好了。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 50010 8 #define Maxm 100010 9 #define INF 0x7fffffff 10 11 int n,m,k; 12 13 int mymin(int x,int y) {return x<y?x:y;} 14 15 struct node 16 { 17 int x,y,c,cc,p,next; 18 }t[Maxm*2]; 19 int first[Maxn],len; 20 21 void ins(int x,int y,int c,int p) 22 { 23 t[++len].x=x;t[len].y=y;t[len].cc=t[len].c=c;t[len].p=p; 24 t[len].next=first[x];first[x]=len; 25 } 26 27 bool cmp(node x,node y) 28 { 29 if(x.c==y.c) return x.p<y.p; 30 return x.c<y.c; 31 } 32 33 int fa[Maxn]; 34 int ffa(int x) 35 { 36 if(fa[x]!=x) fa[x]=ffa(fa[x]); 37 return fa[x]; 38 } 39 40 int tot,now; 41 void check(int x) 42 { 43 tot=0;now=0; 44 for(int i=1;i<=n;i++) fa[i]=i; 45 for(int i=1;i<=len;i++) if(!t[i].p) t[i].c=t[i].cc+x; 46 sort(t+1,t+1+len,cmp); 47 for(int i=1;i<=len;i++) 48 { 49 int x=t[i].x,y=t[i].y; 50 if(ffa(x)!=ffa(y)) 51 { 52 fa[ffa(x)]=ffa(y); 53 if(!t[i].p) tot++; 54 now+=t[i].c; 55 } 56 } 57 } 58 59 int ffind(int l,int r) 60 { 61 int ans=INF; 62 while(l<=r) 63 { 64 int mid=(l+r)>>1;check(mid); 65 if(tot>=k) ans=now-k*mid,l=mid+1; 66 else r=mid-1; 67 } 68 return ans; 69 } 70 71 int main() 72 { 73 scanf("%d%d%d",&n,&m,&k); 74 len=0; 75 memset(first,0,sizeof(first)); 76 int cnt=0; 77 for(int i=1;i<=m;i++) 78 { 79 int x,y,c,p; 80 scanf("%d%d%d%d",&x,&y,&c,&p); 81 x++;y++; 82 if(p==0) cnt++; 83 ins(x,y,c,p);ins(y,x,c,p); 84 } 85 int ans=ffind(-100,100); 86 if(ans==INF) ans=0; 87 printf("%d\n",ans); 88 return 0; 89 }
2017-03-08 21:26:50