【洛谷3237】[HNOI2014] 米特运输(哈希)

点此看题面

  • 给定一棵树,每个数有一个点权。
  • 问最少修改多少点权(可以改为小数),使得:
    • 同一节点各叶节点权值相同。
    • 一个节点的权值等于各叶节点权值之和。
  • (nle5 imes10^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-ans),0;//答案为总点数减去最大保留点数
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3237.html