「HNOI 2014」米特运输

题目链接

戳我

\(Describe\)

谁出的题目啊?这么长的题面,看完就滚粗了.强烈谴责

给一棵树,每个点有一个权值,要求修改一些权值,使:

  1. 一个点的权值必须是其所有儿子的权值之和
  2. 一个点的儿子权值必须相同
    求最少的被修改的数目

\(Solution\)

随便画一画图就可以找到一些显著的规律,只要确定了一个点的权值就可以知道整颗树的值了.

这里就不详细的给出图进行解释了,自己画一画图就可以知道了.

于是我们可以令\(val[x]\)表示\(x\)这个点不变的话,根节点的值.

但是将子节点的个数成起来会爆\(long\ long\),所以需要运用一点小技巧:\(log\)

运用公式:\(log(a*b)=log(a)+log(b)\)

答案就是\(n-val\)数组中相同个数最多的.

\(Code\)

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-6;
int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
struct node {
    int to,next;
}a[500010<<1];
double val[500010];
int v[500010],head[500010],s[500010],cnt;
void add(int x,int y){
    a[++cnt].next=head[x],a[cnt].to=y,head[x]=cnt;
    a[++cnt].next=head[y],a[cnt].to=x,head[y]=cnt;
}
void dfs(int x,int fa,double ans){
    val[x]=ans+log(v[x]),s[x]--;
    for(int i=head[x];i;i=a[i].next){
        int v=a[i].to;
        if(v==fa)
            continue;
        dfs(v,x,ans+log(s[x]));
    }
}
main(){
    int n=read(),x,y,maxx=0,js=1;
    for(int i=1;i<=n;i++)
        v[i]=read();
    for(int i=1;i<n;i++)
        x=read(),y=read(),add(x,y),s[x]++,s[y]++;
    s[1]++,dfs(1,0,0);
    sort(val+1,val+1+n);
    for(int i=2;i<=n;i++){
        if(val[i]-val[i-1]<eps)
            js++;
        else maxx=max(maxx,js),js=1;
    }
    printf("%d",n-maxx);
}
posted @ 2019-02-18 16:25  撤云  阅读(85)  评论(0编辑  收藏  举报
……