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

BZOJ2654 & 洛谷2619:tree——题解

时间:2018-05-12 03:14:50      阅读:196      评论:0      收藏:0      [点我收藏+]

标签:return   hellip   href   最小   +++   个性   namespace   odi   print   

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\n",solve(-100,100));
    return 0;
}

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

+本文作者:luyouqi233。               +

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

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

BZOJ2654 & 洛谷2619:tree——题解

标签:return   hellip   href   最小   +++   个性   namespace   odi   print   

原文地址:https://www.cnblogs.com/luyouqi233/p/9026826.html

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