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; }