BZOJ 3573: [Hnoi2014]米特运输

真正的神题是把OI题出成语文题!

首先我们利用文言文翻译的基本技巧(那是啥)翻译一遍题目

然后就会发现其实就是使得每个点的权值都是父节点权值/父节点的度数

再搞一搞会发现一个点的权值确定了,每个点的权值都确定了

然后根据每个点的权值算出当该点为原值时根节点的权值

排序一下找出现次数最多的那个就可以了

由于权值可能很大,取个对数

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=500000+5;
const double eps=1e-9;
double a[N];
int dcmp(double x){
	if(fabs(x)<eps)return 0;
	return x<0?-1:1;
}
struct Edge{int to,next;}e[N<<1];
int head[N],cnt;
void ins(int u,int v){
	e[++cnt]=(Edge){v,head[u]};head[u]=cnt;
}
void insert(int u,int v){
	ins(u,v);ins(v,u);
}
void dfs(int u,int fa,double sum){
	a[u]=log(a[u])+sum;
	double deg=0.0;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;if(v==fa)continue;
		deg+=1.0;
	}
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;if(v==fa)continue;
		dfs(v,u,sum+log(deg));
	}
}
int main(){
	//freopen("a.in","r",stdin);
	int n;scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lf",&a[i]);
	for(int i=1;i<n;i++){
		int u,v;scanf("%d%d",&u,&v);
		insert(u,v);
	}
	dfs(1,-1,0.0);
	sort(a+1,a+1+n);
	int ans=0;
	for(int i=1,j;i<=n;i=j){
		j=i;
		while(!dcmp(a[j]-a[i]))j++;
		ans=max(ans,j-i);
	}
	printf("%d\n",n-ans);
	return 0;
}


你可能感兴趣的:(BZOJ 3573: [Hnoi2014]米特运输)