• P2619 [国家集训队2]Tree I


    Description

    给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。

    题目保证有解。

    Input

    第一行V,E,need分别表示点数,边数和需要的白色边数。

    接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。

    Output

    一行表示所求生成树的边权和。

    V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。

    Sample Input

    2 2 1
    0 1 1 1
    0 1 2 0

    Sample Output

    2


    先跑一遍最小生成树发现选到的白边数和need是有差距的
    把白边的大小整体上移或下移是对的
    二分偏移量check白边选择量即可
    *注意优先选白边


    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    int i,m,n,j,k,need,l=-150,r=150,tmp,f[100001];
    
    struct vv
    {
    	int x,y,z,c;
    }  a[1000001];
    
    bool cmp(vv a,vv b) {return a.z==b.z? a.c<b.c:a.z<b.z; }
    
    int find(int x)
    {
    	if(f[x]==x) return x;
    	f[x]=find(f[x]);
    	return f[x];
    }
    
    int check(int x)
    {
    	int ans=0; k=0;
    	for(int i=1;i<=m;i++) if(!a[i].c) a[i].z+=x;
    	for(int i=0;i<=n;i++) f[i]=i;
    	sort(a+1,a+1+m,cmp);
    	for(int i=1;i<=m;i++)
    	{
    		if(find(a[i].x)!=find(a[i].y)) 
    		{
    			k+=a[i].z;
    			if(!a[i].c) ans+=1;
    			f[f[a[i].x]]=f[a[i].y];
    		}
    	}
    	for(int i=1;i<=m;i++) if(!a[i].c) a[i].z-=x;
    	return ans;
    }
    
    int main()
    {
    	scanf("%d%d%d",&n,&m,&need);
    	for(i=1;i<=m;i++) 
    		scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].z,&a[i].c);
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(check(mid)>=need)  tmp=mid, l=mid+1;
    		else r=mid-1;
    	}
    	check(tmp);
    	printf("%d",k-tmp*need);
    }
    
  • 相关阅读:
    J2EE第四周
    J2EE 第三周
    jsf简单入门
    Applrt和Ajax
    hello.java分析
    filter用户例子
    分析LogFilter
    理解session
    关于XML
    企业级应用和互联网应用的区别
  • 原文地址:https://www.cnblogs.com/ZUTTER/p/9891000.html
Copyright © 2020-2023  润新知