【BZOJ】2654 tree 二分+kruskal

来源:互联网 发布:女装淘宝代理加盟 编辑:程序博客网 时间:2024/06/06 00:45

题目传送门

好神的想法啊……这个二分好迷啊……

我们可以二分一个值mid,把所有白色的边都加上这个值,在最后计算边权和时减回去,也就相当于改变的白色边的优先级。

然后刷kruskal,如果mst中的白色边数不小于给定的need则验证成功,修改二分的边界继续二分。

附上AC代码:

#include <cstdio>#include <cctype>#include <algorithm>using namespace std;const int N=5e4+10;struct note{    int x,y,w,c;    bool operator < (const note lyf) const {return w==lyf.w?c<lyf.c:w<lyf.w;}}a[N<<1],s[N<<1];int n,m,k,sum,cnt,f[N],l,r,mid,ans;inline char nc(void){    static char ch[100010],*p1=ch,*p2=ch;    return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;}inline void read(int &a){    static char c=nc();int f=1;    for (;!isdigit(c);c=nc()) if (c=='-') f=-1;    for (a=0;isdigit(c);a=(a<<3)+(a<<1)+c-'0',c=nc());    return (void)(a*=f);}inline int gf(int x){return x==f[x]?x:f[x]=gf(f[x]);}inline bool check(int mid){    sum=cnt=0;    for (int i=1; i<=n; ++i) f[i]=i;    for (int i=1; i<=m; ++i) s[i]=a[i],s[i].c==0?s[i].w+=mid:0;    sort(s+1,s+1+m);    for (int i=1; i<=m; ++i){        int fx=gf(s[i].x),fy=gf(s[i].y);        if (fx!=fy){            f[fx]=fy,sum+=s[i].w;            if (!s[i].c) ++cnt;        }    }    return cnt>=k;}int main(void){    read(n),read(m),read(k);    for (int i=1; i<=m; ++i) read(a[i].x),read(a[i].y),read(a[i].w),read(a[i].c),++a[i].x,++a[i].y;    l=-105,r=105;    while (l<r)        if (check(mid=l+r>>1)) l=mid+1,ans=sum-k*mid;        else r=mid-1;    printf("%d\n",ans);    return 0;}
原创粉丝点击