码迷,mamicode.com
首页 > 其他好文 > 详细

P2619 [国家集训队2]Tree I

时间:2018-11-01 19:00:12      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:clu   题目   std   stream   注意   amp   +=   tree   put   

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

标签:clu   题目   std   stream   注意   amp   +=   tree   put   

原文地址:https://www.cnblogs.com/ZUTTER/p/9891000.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!