BZOJ 2654 tree - 二分+最小生成樹

先給出一種方案:
首先二分一個權值mid,然後給白邊每一個邊加上mid,求一個最小生成樹,觀察白邊使用的個數,二分到白邊等於need,ans=val-mid*need。
下面給出證明:
白邊數是一定的,二分權值,mid大,顯然選的白邊數會減少,具有可二分性。
在研究ans的單調性:假設現在有兩種情況,白邊數均爲need,且mid1<mid2 在假設給情況1的白色邊權值都加上Δmid,而選出的邊不變,那麼必然不會更優
(二者的樹形可能都會不一樣,樹形改變則一定不會比原來更差),於是ans1<=valΔmidmid+Δmid=ans2

(胡證的啊我也不知道怎麼證,好捉急啊。。。)

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=50005;

struct edge
{
    int x,y,d,val;
    bool operator < (const edge &x)const
    {
        return val<x.val||(val==x.val&&d<x.d);
    }
}e[maxn<<1];

int n,m,need,sum;
int fa[maxn];

inline int find(int x)
{
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
bool judge(int mid)
{
    int num=0;
    sum=0;
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++)if(!e[i].d)
        e[i].val+=mid;
    sort(e+1,e+m+1);
    for(int i=1;i<=m;i++)
    {
        int x=find(e[i].x);
        int y=find(e[i].y);
        if(x==y)continue;
        fa[x]=y;
        if(!e[i].d)num++;
        sum+=e[i].val;
    }
    for(int i=1;i<=m;i++)if(!e[i].d)
        e[i].val-=mid;
    return num>=need;
}
int main()
{
    scanf("%d%d%d",&n,&m,&need);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].val,&e[i].d);
        e[i].x++;e[i].y++;
    }
    int l=-105,r=105,ans;
    while(l<r)
    {
        int mid=l+r>>1;
        if(judge(mid))
            ans=sum-mid*need,l=mid+1;
        else r=mid;
    }
    printf("%d",ans);
    return 0;
}

發佈了112 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章