2012 年国家集训队互测 Tree

给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有 need条白色边的生成树。题目保证有解


 

感觉不是很懂这道题所谓用need代还cnt的做法

反正bzoj数据水怎么都是对的

#include<bits/stdc++.h>
#define re return
#define ll long long
#define inc(i,l,r) for(int i=l;i<=r;++i)

using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=50005,maxm=100005;
int n,m,sum,need,ans,hd[maxn],fa[maxn];

struct node{
    int fr,to,val,flag;
    bool operator<(node a)const 
    {
        if(val==a.val)re flag<a.flag;
        re val<a.val;
    }
}e[maxm];

inline int find(int x)
{
    re x==fa[x]?x:fa[x]=find(fa[x]);
}

inline int vivi(int x)
{
    inc(i,1,m)if(!e[i].flag)e[i].val+=x;
    
    inc(i,1,n)fa[i]=i;
    
    sort(e+1,e+m+1);
    int cnt=0,tot=0;
    
    sum=0;
    
    inc(i,1,m)
    {
        int f1=find(e[i].fr),f2=find(e[i].to);
        if(f1!=f2)
        {
            ++tot;
            sum+=e[i].val;
            if(!e[i].flag)
                ++cnt;
            fa[f1]=f2;
            if(tot==n-1)break;
        }
    }
    
    inc(i,1,m)
    if(!e[i].flag)
        e[i].val-=x;
    if(cnt<need)re 0;
    ans=sum-cnt*x;
//但是如果是need的话,不是与原来在边权和不等吗 re
1; } int main() { freopen("in.txt","r",stdin); rd(n),rd(m);rd(need); inc(i,1,m) { rd(e[i].fr);rd(e[i].to); ++e[i].fr;++e[i].to; rd(e[i].val);rd(e[i].flag); } int l=-100,r=100; while(l<=r) { int mid=(l+r)>>1; if(vivi(mid)) l=mid+1; else r=mid-1; } printf("%d",ans); re 0; }

 

posted @ 2019-08-26 11:29  凉如水  阅读(342)  评论(0编辑  收藏  举报