把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷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;//答案为总点数减去最大保留点数
}
posted @ 2020-11-04 07:12  TheLostWeak  阅读(63)  评论(0编辑  收藏  举报