真正的神题是把OI题出成语文题!
首先我们利用文言文翻译的基本技巧(那是啥)翻译一遍题目
然后就会发现其实就是使得每个点的权值都是父节点权值/父节点的度数
再搞一搞会发现一个点的权值确定了,每个点的权值都确定了
然后根据每个点的权值算出当该点为原值时根节点的权值
排序一下找出现次数最多的那个就可以了
由于权值可能很大,取个对数
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=500000+5; const double eps=1e-9; double a[N]; int dcmp(double x){ if(fabs(x)<eps)return 0; return x<0?-1:1; } struct Edge{int to,next;}e[N<<1]; int head[N],cnt; void ins(int u,int v){ e[++cnt]=(Edge){v,head[u]};head[u]=cnt; } void insert(int u,int v){ ins(u,v);ins(v,u); } void dfs(int u,int fa,double sum){ a[u]=log(a[u])+sum; double deg=0.0; for(int i=head[u];i;i=e[i].next){ int v=e[i].to;if(v==fa)continue; deg+=1.0; } for(int i=head[u];i;i=e[i].next){ int v=e[i].to;if(v==fa)continue; dfs(v,u,sum+log(deg)); } } int main(){ //freopen("a.in","r",stdin); int n;scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%lf",&a[i]); for(int i=1;i<n;i++){ int u,v;scanf("%d%d",&u,&v); insert(u,v); } dfs(1,-1,0.0); sort(a+1,a+1+n); int ans=0; for(int i=1,j;i<=n;i=j){ j=i; while(!dcmp(a[j]-a[i]))j++; ans=max(ans,j-i); } printf("%d\n",n-ans); return 0; }