P2619 [國家集訓隊2]Tree I
阿新 • • 發佈:2018-11-01
選擇 iostream 一行 turn sin desc algorithm sample -i
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
Sample Output
2
先跑一遍最小生成樹發現選到的白邊數和need是有差距的
把白邊的大小整體上移或下移是對的
二分偏移量check白邊選擇量即可
*註意優先選白邊
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int i,m,n,j,k,need,l=-150,r=150,tmp,f[100001]; struct vv { int x,y,z,c; } a[1000001]; bool cmp(vv a,vv b) {return a.z==b.z? a.c<b.c:a.z<b.z; } int find(int x) { if(f[x]==x) return x; f[x]=find(f[x]); return f[x]; } int check(int x) { int ans=0; k=0; for(int i=1;i<=m;i++) if(!a[i].c) a[i].z+=x; for(int i=0;i<=n;i++) f[i]=i; sort(a+1,a+1+m,cmp); for(int i=1;i<=m;i++) { if(find(a[i].x)!=find(a[i].y)) { k+=a[i].z; if(!a[i].c) ans+=1; f[f[a[i].x]]=f[a[i].y]; } } for(int i=1;i<=m;i++) if(!a[i].c) a[i].z-=x; return ans; } int main() { scanf("%d%d%d",&n,&m,&need); for(i=1;i<=m;i++) scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].z,&a[i].c); while(l<=r) { int mid=(l+r)>>1; if(check(mid)>=need) tmp=mid, l=mid+1; else r=mid-1; } check(tmp); printf("%d",k-tmp*need); }
P2619 [國家集訓隊2]Tree I