BZOJ 2654: tree 二分+最小生成树

code: 

#include <cstdio> 
#include <algorithm> 
#define N 50020  
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;      
struct data 
{
    int x,y,z; 
    data(int a=0,int b=0,int c=0) {x=a,y=b,z=c;}    
    bool operator<(const data a) const { return z<a.z; }   
}b[N<<1],w[N<<1];  
int tb,tw,n,f[N],sum;   
int find(int x) 
{
    return f[x]==x?x:f[x]=find(f[x]); 
}   
int solve(int mid) 
{
    int i,pb=1,pw=1,ans=0;     
    sum=0; 
    for(i=0;i<n;++i) f[i]=i; 
    while(pb<=tb||pw<=tw) 
    {  
        if(pw>tw||(pb<=tb&&b[pb].z<w[pw].z+mid)) 
        {
            if(find(b[pb].x)!=find(b[pb].y)) 
            {
                sum+=b[pb].z;  
                f[f[b[pb].x]]=f[b[pb].y];        
            }
            ++pb; 
        }
        else 
        {
            if(find(w[pw].x)!=find(w[pw].y)) 
            {
                sum+=w[pw].z;  
                f[f[w[pw].x]]=f[w[pw].y];       
                ++ans;   
            }
            ++pw; 
        }
    }
    return ans; 
}
int main() 
{ 
    // setIO("input");  
    int i,j,m,k,x,y,z,p,l=-100,r=100,mid,ans;   
    scanf("%d%d%d",&n,&m,&k);   
    for(i=1;i<=m;++i) 
    {
        scanf("%d%d%d%d",&x,&y,&z,&p);    
        if(p) b[++tb]=data(x,y,z); 
        else w[++tw]=data(x,y,z);   
    } 
    sort(b+1,b+1+tb); 
    sort(w+1,w+1+tw);    
    while(l<=r) 
    {
        mid=(l+r)>>1;    
        if(solve(mid)>=k) ans=mid,l=mid+1; 
        else r=mid-1; 
    } 
    solve(ans); 
    printf("%d\n",sum); 
    return 0; 
}

  

posted @ 2019-12-23 16:44  EM-LGH  阅读(123)  评论(0编辑  收藏  举报