1. 程式人生 > >WQS二分 Tree I

WQS二分 Tree I

讓我們一起來%forever_shi神犇

題意:
給你一個無向帶權連通圖,每條邊是黑色或白色。讓你求一棵最小權的恰好有k條白色邊的生成樹。
題解:
看的別人的題解。
做法是二分一個權值,可正可負,讓所有白色邊加上這個權值,然後再做最小生成樹,顯然這個全權值是可以二分的。
然後最後每次二分得到的結果再加上那些減去的權值就是這種最小生成樹的權值和了。
另外權值相同的時候據說需要先選白色邊。

神奇做法,據說可以證明,但我不會啊QAQ,當套路記吧。。。

#include<bits/stdc++.h>
using namespace std;
int n,m,k,f[1001000
],tot,res; struct node { int x,y,c,col; }e[1001000],a[1001000]; int find(int x) { if(x==f[x]) return x; else { f[x]=find(f[x]); return f[x]; } } bool cmp(node n1,node n2) { if(n1.c!=n2.c) return n1.c<n2.c; else return n1.col<n2.col; } bool
check(int x) { int numw=0,t=0; tot=0; for(int i=1;i<=n;++i) f[i]=i; for(int i=1;i<=m;++i) a[i]=e[i]; for(int i=1;i<=m;++i) if(e[i].col==0) a[i].c+=x; sort(a+1,a+m+1,cmp); for(int i=1;i<=m;++i) { int fx=find(a[i].x);
int fy=find(a[i].y); if(fx!=fy) { f[fx]=fy; if(a[i].col==0) numw++; tot+=a[i].c; t++; if(t==n-1) break; } } if(numw>=k) return true; else return false; } int main() { cin>>n>>m>>k; for(int i=1;i<=m;++i) scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].c,&e[i].col); for(int i=1;i<=m;++i) { e[i].x++; e[i].y++; } int l=-50000,r=50000,ans=0; while(l<=r) { int mid=(l+r)/2; if(check(mid)) { l=mid+1; ans=mid; res=tot-ans*k; } else r=mid-1; } cout<<res; return 0; }