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