bzoj 2654 tree

题目:tree

思路:
假设给所有百边加上一个值mid,此时刚好的最小生成树用了Need条百边,那么此时所求的解为s-mid*need,其中s为最小生成树大小。
此时二分mid即可。
只是不知道为什么代码比别人的长很多Orz……

代码:

#include<bits/stdc++.h>
using namespace std;

#define maxn 50000
#define maxm 100000
#define inf 100

struct Edge {
    int x,y,z,col;
    Edge() {}
    Edge(int xx,int yy,int zz,int c) {
        x=xx,y=yy,z=zz,col=c;
    }
    bool operator < (const Edge& oth) const {
        return z<oth.z||(z==oth.z&&col<oth.col);
    }
};

int n,m,Need;
Edge a[maxm+5];
Edge b[maxm+5];

int fa[maxm+5]={0};
int s=0;

void readin() {
    scanf("%d%d%d",&n,&m,&Need);
    for(int i=1; i<=m; i++) {
        scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].z,&a[i].col);
    }
}

void add(int x) {
    for(int i=1; i<=m; i++) {
        b[i]=a[i];
        if(!a[i].col) b[i].z+=x;
    }
}

int find(int x) {
    if(fa[x]==-1) return x;
    else return fa[x]=find(fa[x]);
}

int kruskal() {
    int ans=0;
    s=0;
    for(int i=1;i<=m;i++) {
        int fa1=find(b[i].x),fa2=find(b[i].y);
        if(fa1!=fa2) {
            fa[fa1]=fa2;
            ans+=(!b[i].col);
            s+=b[i].z;
        }
    }
    return ans;
}

bool check(int x) {
    add(x);
    sort(b+1,b+m+1);
    memset(fa,-1,sizeof(fa));
    int ans=kruskal();
    return ans>=Need;
}

int binsearch() {
    int l=-inf,r=inf;
    while(l+1<r) {
        int mid=l+(r-l)/2;
        if(check(mid)) l=mid;
        else r=mid;
    }
    if(check(l+1)) l++;
    if(!check(l)) l--;
    return l;
}

int main() {
    readin();
    int ans=binsearch();
    check(ans);
    printf("%d",s-ans*Need);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/rabbit_ZAR/article/details/81708847