最小生成树 tree(陈立杰)

来源:互联网 发布:库里总决赛场均数据 编辑:程序博客网 时间:2024/05/29 16:12

问题 D: tree
时间限制: 3 Sec 内存限制: 512 MB
提交: 24 解决: 7
[提交][状态][讨论版]
题目描述
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
输入
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
输出
一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
样例输入
2 2 1
0 1 1 1
0 1 2 0
样例输出
2
因为当前最小生成树上的白边是不确定的,所以通过修改白边的优先级来改变生成树上白边的数量。那么怎么修改呢?改边权。当然就想到二分答案了,给白边加上当前二分的值(-100,100)如果白边过多,加大值,过少反之。
注意,会有很多边边权一样,这时,白边数量q>k也可以是成立的(只要把一些等权的白边改成黑边就行了)注意最后答案要减去need*mid(二分的值)

     #include<cstdlib>#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int n,m,k,mid,e,ans,q,adj[50005],f[50005];struct road{    int u,v,next,l,h;    bool friend operator <(road a,road b)    {        return a.l!=b.l ? a.l<b.l : a.h<b.h;    }}lu[100005];void add(int u,int v,int l,int h){lu[++e].u=u;lu[e].h=h;lu[e].v=v;lu[e].l=l;lu[e].next=adj[u];adj[u]=e;}inline int find(int x){return f[x]==x ? x:f[x]=find(f[x]);}inline void hb(int x,int y){int fx=find(x),fy=find(y);if(fx!=fy)f[fx]=fy;}inline 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<<1)+(sum<<3)+x-'0';x=getchar();}    return sum*f;}int check(){    ans=0;q=0;int w=0;    for(int i=1;i<=m;i++)if(!lu[i].h)lu[i].l+=mid;    sort(lu+1,lu+m+1);    for(int i=0;i<n;i++)f[i]=i;    for(int i=1;i<=m;i++)    {        if(find(lu[i].u)!=find(lu[i].v))        {            w++;            hb(lu[i].u,lu[i].v);            ans+=lu[i].l;            if(!lu[i].h)q+=1;        }        if(w==n-1)break;    }    for(int i=1;i<=m;i++)if(!lu[i].h)lu[i].l-=mid;    //cout<<q<<" "<<ans<<endl;    if(q>=k)return 1;    return 0;}int yjn(){//  freopen("nt2012_tree.in","r",stdin);//  freopen("nt2012_tree.out","w",stdout);    scanf("%d%d%d",&n,&m,&k);    int x,y,z,h;    for(int i=1;i<=m;i++)    {        x=read();y=read();z=read();h=read();        add(x,y,z,h);    }    int l=-100,r=100,w=0;    while(l<=r)    {        mid=(l+r)/2;        if(check())      {           l=mid+1,w=ans-k*mid;       }       else r=mid-1;   }    cout<<w;}int qty=yjn();int main(){;}