【洛谷3237】[HNOI2014] 米特运输(哈希)
- 给定一棵树,每个数有一个点权。
- 问最少修改多少点权(可以改为小数),使得:
- 同一节点各叶节点权值相同。
- 一个节点的权值等于各叶节点权值之和。
- \(n\le5\times10^5\)
哈希
考虑根据题目中给出的性质,确定一个点权实际上就确定了整棵树。
于是我们求出每个点保持其权值不变时根节点的权值。
如果若干点权值不变时根节点权值相同,它们就可以一起保留。
哈希一下就好了。
代码:\(O(nlogn)\)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 500000
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
#define mp make_pair
#define fi first
#define se second
#define X1 20050413
#define X2 20201024
using namespace std;
int n,a[N+5],ee,lnk[N+5];struct edge {int to,nxt;}e[N<<1];
map<pair<int,int>,int> p;int ans;
I void dfs(CI x,CI lst,pair<int,int> o)//直接用pair来哈希
{
ans=max(ans,++p[mp(1LL*o.fi*a[x]%X1,1LL*o.se*a[x]%X2)]);//统计最大的相同哈希值数
RI i,t=0;for(i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&++t;o=mp(1LL*o.fi*t%X1,1LL*o.se*t%X2);//统计子节点个数,以得出当前点和子节点权值倍数关系
for(i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&(dfs(e[i].to,x,o),0);//递归
}
int main()
{
RI i;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d",a+i);
RI x,y;for(i=1;i^n;++i) scanf("%d%d",&x,&y),add(x,y),add(y,x);
return dfs(1,0,mp(1,1)),printf("%d\n",n-ans),0;//答案为总点数减去最大保留点数
}
待到再迷茫时回头望,所有脚印会发出光芒