zoukankan      html  css  js  c++  java
  • BZOJ2654 & 洛谷2619:tree——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=2654

    https://www.luogu.org/problemnew/show/P2619

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

    在APIO重学了二分……cljls的可怕题目!

    如果不知道wqs二分(DP凸优化/带权二分?)的话应该是没什么思路的。

    对每条白边加整数w,如果w过小则求得的生成树大部分为白边,反之大部分为黑边。

    于是利用这个性质二分w,且正好当符合条件时求得的生成树就正是题目所求得生成树。

    为什么呢?显然我们拿的白边是所有白边当中最好的(权值最小的),且由于kruskal的正确性不难知道其正确性。

    PS:当边权相等时优先添加白边!

    #include<queue>
    #include<cmath>
    #include<stack>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=50005;
    const int M=100005;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct node{
        int u,v,w,c;
    }e[M];
    int n,m,t,tmp,fa[N];
    int find(int x){
        if(fa[x]==x)return x;
        return fa[x]=find(fa[x]);
    }
    inline void unionn(int u,int v){
        fa[u]=v;
    }
    inline bool cmp(node a,node b){
        return a.w<b.w||(a.w==b.w&&a.c<b.c);
    }
    void modify(int k){
        for(int i=1;i<=m;i++){
            if(!e[i].c)e[i].w+=k;
        }
    }
    bool pan(int k){
        modify(k);
        sort(e+1,e+m+1,cmp);
        int num=0,cnt=0;tmp=0;
        for(int i=1;i<=n;i++)fa[i]=i;
        for(int i=1;i<=m;i++){
            int u=e[i].u,v=e[i].v,w=e[i].w;
            u=find(u),v=find(v);
            if(u!=v){
                unionn(u,v);
                cnt++;tmp+=w;
                if(!e[i].c)num++;
                if(cnt==n-1)break;
            }
        }
        modify(-k);
        return num>=t;
    }
    int solve(int l,int r){
        int ans;
        while(l<r){
            int mid=(l+r+1)>>1;
            if(!pan(mid))r=mid-1;
            else{
                l=mid;
                ans=tmp-mid*t;
            }
        }
        return ans;
    }
    int main(){
        n=read(),m=read(),t=read();
        for(int i=1;i<=m;i++){
            e[i].u=read()+1,e[i].v=read()+1;
            e[i].w=read(),e[i].c=read();
        }
        printf("%d
    ",solve(-100,100));
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    Jmeter之Bean shell使用(一)
    CSS知识点 2
    0523 CSS知识点
    0522 HTML表单 CSS基础
    0521 HTML基础
    0515线程
    0514 队列 管道 进程池 回调函数
    0510进程 multiprocess模块
    0509操作系统发展史 进程
    0507黏包
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9026826.html
Copyright © 2011-2022 走看看