BZOJ3573 [Hnoi2014]米特运输 【贪心】

题目链接

BZOJ3573

题解

题目又臭又长系列

题意:修改尽量少的点权,使得:
①同个节点的所有儿子点权相同
②任意非叶节点权值等于其儿子权值之和

容易发现一旦任意一个点权值确定,整棵树权值就确定
一个比较简单的想法是枚举根节点权值

但我们可以通过计算出每个节点如若保留原值,根节点会是什么值
如果两个节点能同时不变,当且仅当它们对应根节点权值相等
我们算出来排序选择权值最多的那一个就好了
直接乘会爆\(long long\),可使用\(log\)转化为加法

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
#define eps 1e-9
using namespace std;
const int maxn = 500005,maxm = 1000005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
int tot;
double H[maxn];
int n,val[maxn],de[maxn];
int h[maxn],ne = 1;
struct EDGE{int to,nxt;}ed[maxm];
inline void build(int u,int v){
    ed[++ne] = (EDGE){v,h[u]}; h[u] = ne;
    ed[++ne] = (EDGE){u,h[v]}; h[v] = ne;
    de[u]++; de[v]++;
}
double v[maxn];
int fa[maxn];
void dfs(int u){
    if (u == 1) v[u] = log(1);
    else v[u] = v[fa[u]] + log(fa[u] == 1 ? de[fa[u]] : de[fa[u]] - 1);
    H[++tot] = v[u] + log(val[u]);
    Redge(u) if ((to = ed[k].to) != fa[u]){
        fa[to] = u; dfs(to);
    }
}
int main(){
    n = read();
    REP(i,n) val[i] = read();
    for (int i = 1; i < n; i++) build(read(),read());
    dfs(1);
    int ans = 0,cnt = 0;
    sort(H + 1,H + 1 + tot);
    for (int i = 1; i <= tot; i++){
        if (fabs(H[i] - H[i - 1]) > eps) ans = max(ans,cnt),cnt = 1;
        else cnt++;
    }
    ans = max(ans,cnt);
    printf("%d\n",n - ans);
    return 0;
}