• tree (一本通练习||清华集训互测)


    tree

    内存限制:512 MiB 时间限制:3000 ms 标准输入输出
    题目类型:传统 评测方式:文本比较
     

    题目描述

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

    输入格式

    第一行V,E,need分别表示点数,边数和需要的白色边数。
    接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。

    输出格式

    一行表示所求生成树的边权和。
    V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。

    样例

    样例输入

    2 2 1
    0 1 1 1
    0 1 2 0

    样例输出

    2

    数据范围与提示

    原数据出错,现已更新 by liutian,但未重测---2016.6.24

    也是一个做法比较玄学的题

    二分答案,考虑我们往白边上加值或者减值,那么就会对应的少选白边或者少选黑边

    那么如果当前  白边+mid如果kuskal选择白边比need多就继续往上面加值,如果选择白边比need少就往下减值

    因为kuskal保证图一定连通,并且代价最小。所以保证了正确性

    #include<bits/stdc++.h>
    #define ll long long
    #define A 10000000
    using namespace std;
    struct edge{
        ll x,y,z,id;
        ll flag;
    }e[A];
    ll n,m,need,fa[A],zong,ans,end[A];
    inline ll read()
    {
        ll f=1,x=0;char c=getchar();
        while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return f*x;
    }
    ll find(ll x)
    {
        if(fa[x]!=x) fa[x]=find(fa[x]);
        return fa[x];
    }
    void hebing(ll x,ll y)
    {
        x=find(x),y=find(y);    if(x!=y) fa[y]=x;
    }
    bool cmp(edge a,edge b){return (a.z==b.z)?(a.flag<b.flag):(a.z<b.z);}
    inline void kuskar(ll mid)
    {
        for(ll i=0;i<=n;i++)
            fa[i]=i;
        zong=0,ans=0;
        for(ll i=1;i<=m;i++)
        if(!e[i].flag)
            e[i].z+=mid;
        sort(e+1,e+m+1,cmp);
        for(ll i=1;i<=m;i++)
        {
            if(find(e[i].x)!=find(e[i].y))
            {
                if(!e[i].flag)
                    zong++;
                hebing(e[i].x,e[i].y);
                ans+=e[i].z;
            }
        }
        for(ll i=1;i<=m;i++)
            if(!e[i].flag)
                e[i].z-=mid;
    }
    int main()
    {
        ll tot=0;
        n=read(),m=read(),need=read();
        for(ll i=1;i<=m;i++)
            e[i].x=read(),e[i].y=read(),e[i].z=read(),e[i].flag=read();
        ll l=-100,r=100;
        while(l<=r)
        {
            ll mid=(l+r)>>1;
            kuskar(mid);
            if(zong>=need) l=mid+1,tot=ans-need*mid;
            else r=mid-1;
        }
        cout<<tot<<endl;
    }
    View Code
    我已没有下降的余地
  • 相关阅读:
    [Flex] Flex 控件&类 的自定义事件添加
    [java]原始类型和其包装类
    [java]解析网络上的xml文件
    [android]用adb操作android模拟器
    [java]优先队列
    [Q&A]为什么在ospf邻居之间确定主从关系?
    [js]jQuery插件开发总结
    [Q&A] 为什么把js脚本放到html页面的底部?
    理解一个简单的网页请求过程
    [js]如何更快的得到图片的高度和宽度
  • 原文地址:https://www.cnblogs.com/znsbc-13/p/11202606.html
Copyright © 2020-2023  润新知