zoukankan      html  css  js  c++  java
  • BZOJ2654 tree

    一开始打了个贪心,求最小生成树,白边多就把权值最大的白边干掉,白边少就把权值最大的黑边干掉,因为数据肯定有解嘛。结果大点TLE,小点只过了一个。事实证明,贪心有时真的不能瞎用。

    其实这个二分还是挺有道理的,给白边加权值,则入选白边会减少,给白边减权值,则入选白边增加,二分枚举这个权值,白边多了则向大枚举,白边少了则向小枚举,思路蛮简单的。

    剩下的就是二分的细节了。试了无数遍,终于找到了最合适的二分方法,而且等号最好放在大于号那里,因为恰好有need条白边以后ans还不一定最优,应该尝试着在白边不变的基础上,把更优秀的黑边加进来,需要把白边排斥一下。

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<set>
    #include<map>
    using namespace std;
    struct EDGE{
        int st,ed,nex,val,col;
    }edge[2005000];int num,first[500050];
    int read(){
        int sum=0,f=1;char x=getchar();
        while(x<'0'||x>'9'){
            if(x=='-') f=-1;
            x=getchar();
        }while(x>='0'&&x<='9'){
            sum=sum*10+x-'0';
            x=getchar();
        }return sum*f;
    }
    int n,m,need,ans,ans2,fa[500500];
    void add(int st,int ed,int val,int col){
        edge[++num].st=st;
        edge[num].ed=ed;
        edge[num].val=val;
        edge[num].col=col;
        edge[num].nex=first[st];
        first[st]=num;
    }
    bool camp(EDGE a,EDGE b){
        if(a.val==b.val) return a.col>b.col;
        return a.val<b.val;
    }
    int get(int x){
        return x==fa[x]?x:fa[x]=get(fa[x]);
    }
    bool check(int x){
    //    cout<<"mid="<<x<<endl;
        int color=0,sum=0;
        ans=0;
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=num;i++) 
            if(edge[i].col) edge[i].val+=x;
        sort(edge+1,edge+1+num,camp);
        for(int i=1;i<=num;i++){
            int x=edge[i].st,y=edge[i].ed;
            x=get(x);y=get(y);
            if(x==y) continue;
            fa[x]=y;
            color+=edge[i].col;
            ans+=edge[i].val;
            sum++;
            if(sum==n-1) break;
        }
        for(int i=1;i<=num;i++)
            if(edge[i].col) edge[i].val-=x;
    /*    cout<<color<<" "<<endl;
        for(int i=1;i<=num;i++){
            cout<<edge[i].val<<" ";
        }cout<<endl;*/
    //    fgetc(stdin);
        return color>=need;
    }
    int main(){
        n=read();m=read();need=read();
        for(int i=1;i<=m;i++){
            int st=read(),ed=read(),val=read(),col=read();
            add(st+1,ed+1,val,col^1);
        }
        int l=-102,r=102;
        while(l<r){
        //    cout<<l<<" "<<r<<endl;
            int mid=l+r>>1;
            if(check(mid)){ 
                l=mid+1;
                ans2=ans-need*mid;
            }
            else r=mid;
    
        }printf("%d",ans2);
        return 0;
    }
    View Code
  • 相关阅读:
    kafka学习总结010 --- 实际项目中遇到的问题1
    kafka学习总结009 --- HW和LEO
    spring学习总结001 --- IOC控制反转、DI依赖注入
    kafka学习总结008 --- 生产者生产数据流程(参照源码)
    kafka学习总结007 --- 生产者Java API实例
    kafka学习总结006 --- 生产者事务
    kafka学习总结005 --- at-exactly-once语义
    kafka学习总结004 --- 生产者ISR
    kafka学习总结003 --- 生产者分区策略
    计算机基础-1(进制转换)
  • 原文地址:https://www.cnblogs.com/Yu-shi/p/11177856.html
Copyright © 2011-2022 走看看