[CF444E]DZY Loves Planting

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF444E]DZY Loves Planting相关的知识,希望对你有一定的参考价值。

题意:给一棵带边权的树,定义$g(x,y)$为$x\\rightarrow y$路径上的最大边权,对于整数序列$p_{1\\cdots n}$,定义$f(p)=\\min\\limits_{i=1}^ng(i,p_i)$,求$p_i$的最大值,还有限制:数字$j$在$p$中不能出现多于$x_j$次

这题......好像原出题人想到二分答案+网络流,被某神犇的并查集完虐了......

把边从小到大排序,扫一遍检查每条边能否成为答案,然后把这两个点合并(因为已合并的边都不大于当前扫到的边)

关键在于怎么检查,设$cnt_i$表示节点$i$已合并的点的$x_j$之和,$siz_i$表示节点$i$已合并的点数,$sum=\\sum\\limits_{j=1}^nx_j$

设当前扫到$(a,b)$这条边,我们要把$a$已合并的点连出去

技术分享图片

因为在($a$已合并的点和$b$已合并的点)中的边都不比$(a,b)$大,所以这样就能让比$(a,b)$小的边不在$p$中

因为所有$a$已合并的点都要向外连出去,所以可以连的条件自然就是$siz_a\\leq sum-cnt_a$

所以我们用并查集维护$cnt,siz$边合并边检查,就搞定了

#include<stdio.h>
#include<algorithm>
using namespace std;
struct edge{
	int a,b,v;
}e[3010];
int fa[3010],siz[3010],cnt[3010],sum;
bool can;
bool operator<(edge a,edge b){
	return a.v<b.v;
}
int getfa(int x){
	if(fa[x]==x)return x;
	return fa[x]=getfa(fa[x]);
}
void merge(int x,int y){
	x=getfa(x);
	y=getfa(y);
	siz[x]+=siz[y];
	cnt[x]+=cnt[y];
	fa[y]=x;
	if(siz[x]>sum-cnt[x])can=0;
}
int main(){
	int n,i,ans;
	scanf("%d",&n);
	for(i=1;i<n;i++)scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].v);
	for(i=1;i<=n;i++){
		scanf("%d",cnt+i);
		sum+=cnt[i];
		siz[i]=1;
		fa[i]=i;
	}
	sort(e+1,e+n);
	ans=0;
	can=1;
	for(i=1;i<n;i++){
		if(can)ans=e[i].v;
		merge(e[i].a,e[i].b);
	}
	printf("%d",ans);
}

以上是关于[CF444E]DZY Loves Planting的主要内容,如果未能解决你的问题,请参考以下文章

CF446A DZY Loves Sequences 简单dp

CF444E. DZY Loves Planting

CF446D. DZY Loves Games

CF446C [DZY loves Fibonacci]

(CF)Codeforces445A DZY Loves Chessboard(纯实现题)

CF446C DZY Loves Fibonacci Numbers 线段树 + 数学