Luogu2619[國家集訓隊2] Tree I
阿新 • • 發佈:2018-11-06
原題連結:https://www.luogu.org/problemnew/show/P2619
Tree I
題目描述
給你一個無向帶權連通圖,每條邊是黑色或白色。讓你求一棵最小權的恰好有need條白色邊的生成樹。
題目保證有解。
輸入輸出格式
輸入格式:
第一行V,E,need分別表示點數,邊數和需要的白色邊數。
接下來E行
每行s,t,c,col表示這邊的端點(點從0開始標號),邊權,顏色(0白色1黑色)。
輸出格式:
一行表示所求生成樹的邊權和。
輸入輸出樣例
輸入樣例#1:
2 2 1
0 1 1 1
0 1 2 0
輸出樣例#1:
2
說明
0:V<=10
1,2,3:V<=15
0,…,19:V<=50000,E<=100000
所有資料邊權為[1,100]中的正整數。
By WJMZBMR
題解
帶權二分第一題。。。
如果白色邊的權值都加上 ,最小生成樹中的白色邊會盡量少;如果白色邊權值都加上 ,最小生成樹中的白色邊就會盡量多。
所以我們二分白色邊的附加權值,每次做 ,看白邊有幾條,最後輸出答案即可。
程式碼
#include<bits/stdc++.h>
#define inf 100
using namespace std;
const int M=1e5+5;
struct sd{int a,b,val,col;}ed[M],now[M];
bool operator<(sd a,sd b){return a.val==b.val?a.col<b.col:a.val<b.val;}
int f[M],n,m,need,cot,tot,ans;
int root(int v){return f[v]==v?v:f[v]=root(f[v]);}
bool check(int d)
{
ans=cot=tot=0;
for(int i=1;i<=n;++i)f[i]=i;
for(int i=1;i<=m;++i)now[i]=ed[i],now[i].val+=(ed[i].col?0:d);
sort(now+1,now+1+m);
for(int i=1;i<=m&&tot<n;++i)if(root(now[i].a)!=root(now[i].b))
f[f[now[i].a]]=f[now[i].b],cot+=(now[i].col^1),ans+=now[i].val,++tot;
return cot>=need;
}
void in()
{
scanf("%d%d%d",&n,&m,&need);
for(int i=1,a,b,c,d;i<=m;++i)
scanf("%d%d%d%d",&a,&b,&c,&d),ed[i]=(sd){a+1,b+1,c,d};
}
void ac()
{
int l=-inf,r=inf,mid,d;
for(;l<=r;mid=l+r>>1,check(mid)?(l=mid+1,d=mid):r=mid-1);
check(d);printf("%d",ans-need*d);
}
int main(){in(),ac();}