bzoj3573: [Hnoi2014]米特运输

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3573

思路:语文题...

正常题意:

给定一棵树和每个点的权值,问最少改动多少个点的权值使得:

1.每个点的所有儿子权值相等

2.每个点的权值等于所有儿子权值和


既然有这两个条件,那我们确定一个点的权值就确定了整棵树所有点的权值。

枚举每个点不变,算出根节点的权值,选出现次数最多的方案,那么改动的点数就是n-方案数,此时最小

因为根节点权值很大,取log或hash即可。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=500010,maxm=1000010;
const double eps=1e-7;
using namespace std;
int n,a[maxn],pre[maxm],now[maxn],son[maxm],cnt[maxn],fa[maxn],val[maxn],res,tot;double s[maxn],ans[maxn];
void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
void dfs1(int x){for (int y=now[x];y;y=pre[y]) if (fa[x]!=son[y]) cnt[x]++,fa[son[y]]=x,dfs1(son[y]);}
void dfs2(int x){
	for (int y=now[x];y;y=pre[y]) if (son[y]!=fa[x])
		s[son[y]]=s[x]+log(cnt[x]),dfs2(son[y]);
}

int main(){
	scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&val[i]);
	for (int i=1,a,b;i<n;i++) scanf("%d%d",&a,&b),add(a,b),add(b,a);
	dfs1(1),s[1]=log(1.0),dfs2(1);
	for (int i=1;i<=n;i++) ans[i]=s[i]+log(val[i]);
	sort(ans+1,ans+1+n);
	int cnt=0;
	for (int i=1;i<=n;i++){
		if (fabs(ans[i]-ans[i-1])<eps) cnt++;
		else res=max(res,cnt),cnt=1;
	}
	res=max(res,cnt),printf("%d\n",n-res);
	return 0;
}


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