zoukankan      html  css  js  c++  java
  • 「BZOJ2654」tree

    「BZOJ2654」tree

    最小生成树+二分答案。

    最开始并没有觉得可以二分答案,因为答案并不单调啊。

    其实根据题意,白边的数目肯定大于need条,而最小生成树的白边数并不等于need(废话),可以二分将每条白边的权值+mid,这样就可以控制最小生成树中白边的条数,

    对于一个mid,将所有的白边权值加mid,然后跑kruskal,求出最小生成树中白边的个数num以及此时的权值和ans(要减去mid*need),如果num=need直接输出ans,如果num<need

    则让r=mid继续二分,如果num>need,则要记录一下此时的答案(注意此时的答案并不是ans-mid*num,而是ans-mid*need),因为有可能会出现如下情况:要求8条白边,mid=0时num=12,mid=1时num=0,无法是num恰好等于need,此时记录的数据就是答案。

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #define INF 0x7fffffff
    using namespace std;
    struct edge
    {
    	int u,v,w,c,nxt;
    	#define u(x) ed[x].u
    	#define v(x) ed[x].v
    	#define w(x) ed[x].w
    	#define c(x) ed[x].c
    	#define n(x) ed[x].nxt
    	friend bool operator < (edge a,edge b)
    	{return a.w==b.w?(a.c<b.c):(a.w<b.w);}
    }ed[100010];
    int first[50010],num_e;
    #define f(x) first[x]
    int f[50010];
    int v,e,n,nb;
    int l=-500,r=500,mid,ans,eans=INF;
    
    int getf(int x){return (f[x]==x)?x:f[x]=getf(f[x]);}
    void hb(int x,int y){x=getf(x),y=getf(y),f[y]=x;}
    inline void add(int u,int v,int w,int c);
    int kruskal()
    {
    	int num=0;ans=0;
    	for(int i=0;i<=v;i++)f[i]=i;
    	sort(ed+1,ed+num_e+1);
    	for(int i=1;i<=num_e;i++)
    	if(getf(u(i))!=getf(v(i)))
    	{
    		ans+=w(i);
    		hb(u(i),v(i));
    		if(!c(i))num++;
    	}
    	return num;
    }
    signed main()
    {
    //	freopen("9.in","r",stdin);
    //	freopen("in.txt","r",stdin);
    
    	scanf("%d%d%d",&v,&e,&n);
    	for(int i=0;i<=v;i++)f[i]=i;
    	int s,t,w,c;
    	for(int i=1;i<=e;i++)
    	{
    		scanf("%d%d%d%d",&s,&t,&w,&c);
    		add(s,t,w,c);
    		if(!c)nb++;
    	}
    	sort(ed+1,ed+num_e+1);
    	int num;
    	while(l<r-1)
    	{
    		mid=(l+r)>>1;
    		for(int i=1;i<=num_e;i++)if(!c(i))w(i)+=mid;
    		num=kruskal();
    		if(num==n){printf("%d
    ",ans-mid*num);return 0;}
    		else if(num<n)r=mid;
    		else {l=mid;eans=ans-mid*n;}
    		for(int i=1;i<=num_e;i++)if(!c(i))w(i)-=mid;
    	}
    	printf("%d
    ",eans);
    }
    inline void add(int u,int v,int w,int c)
    {
    	++num_e;
    	u(num_e)=u;
    	v(num_e)=v;
    	w(num_e)=w;
    	c(num_e)=c;
    	n(num_e)=f(u);
    	f(u)=num_e;
    }
    
     
  • 相关阅读:
    i++与++i的区别和使用
    C++中函数返回引用
    ASP.NET金课设计(四)
    ASP.NET金课设计(三)
    ASP.NET金课设计(二)
    ASP.NET金课--课程大纲
    使用PagerTemplate实现GridView分页
    后台模块--订单管理
    前台模块--首页
    后台模块--公告管理
  • 原文地址:https://www.cnblogs.com/Al-Ca/p/11178564.html
Copyright © 2011-2022 走看看