• CF444E DZY Loves Planting 并查集


    题意:

    给定一颗大小为\(n\)的树,定义\(g(i,j)\)表示树上\(i\)\(j\)点路径上,最大的一个边权,现在要求你给树上每一个点\(i\)选择一个点\(j\)进行配对,每一个点最多被选\(x_i\)次,使得\(min\ g(i,j)\)最大

    范围&性质: \(1\le n\le 3000,1\le x_i\le n\)

    分析:

    暴力做法:

    二分答案,check()的时候通过带权二分图匹配的方法进行调整,复杂度为\(O(n^3log)\)想到了,不过因为码量不小考场上没写出来

    正解:

    对所有边进行排序,从小到大枚举,对于每一个边所连接的两个连通块如果不得不经过这条边时,答案即为这条边的边权,那么对于什么情况下存在点不得不经过这条边,换句话说就是无法通过配对使得联通块内每一个点都有不经过这条边的选择,转换成代码的话,我们记\(sum\)为连通块内部\(x_i\)的和,\(siz\)为连通块的大小,当\(siz>\sum_{i=1}^n x_i-sum\)不得不经过这条边,复杂度\(O(nlog)\)

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
    	const int maxn = 3005;
    	int n,sum;
    	int fa[maxn],siz[maxn],x[maxn];
    	
    	struct edge
    	{
    		int frm,to,val;
    	}e[maxn];
    	
    	bool cmp(edge a,edge b)
    	{
    		return a.val<b.val;
    	}
    	
    	int find(int x)
    	{
    		return fa[x]==x?x:fa[x]=find(fa[x]);
    	}
    	
    	void work()
    	{
    		scanf("%d",&n);
    		for(int i=1;i<n;i++)
    		{
    			scanf("%d%d%d",&e[i].frm,&e[i].to,&e[i].val);
    		}
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%d",&x[i]);
    			sum+=x[i];
    		}
    		for(int i=1;i<=n;i++)
    		{
    			fa[i]=i;siz[i]=1;
    		}
    		sort(e+1,e+n,cmp);
    		for(int i=1;i<=n-1;i++)
    		{
    			int u=e[i].frm;
    			int v=e[i].to;
    			int fx=find(u);
    			int fy=find(v);
    			fa[fy]=fx;
    			siz[fx]+=siz[fy];
    			x[fx]+=x[fy];
    			if(siz[fx]>sum-x[fx])
    			{
    				printf("%d\n",e[i].val);
    				return ;
    			}
    		}
    		printf("%d\n",e[n-1].val);
    	}
    	
    }
    
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    其它人的面试
    面试准备——(一)测试基础(3)测试用例的编写
    面试准备——(三)Selenium(1)基础问题及自动化测试
    HTTP简介,http是一个属于应用层的面向对象的协议
    fidder(介绍)
    软件测试基础知识大全
    为什么要走川藏线(人文版)(转)
    将Windows 8.1 系统窗口背景设置成淡绿色?
    如何看待淘宝二手交易APP“闲鱼”推出的新功能“闲鱼小法庭”?
    轻轻松松种绿豆
  • 原文地址:https://www.cnblogs.com/youth518/p/13677485.html
Copyright © 2020-2023  润新知