您的位置:首页 > 其它

BZOJ_3573_[Hnoi2014]米特运输_树形DP+hash

2018-03-12 20:27 489 查看

BZOJ_3573_[Hnoi2014]米特运输_树形DP+hash

题意:

给你一棵树每个点有一个权值,要求修改最少的权值,使得每个节点的权值等于其儿子的权值和且儿子的权值都相等。

 

分析:

首先我们发现在树中如果确定一个点的权值,那么整颗树的方案就能够确定

问题转化成求哪个方案包含的点最多

如何求包含这个点的是哪个方案?

可以给每个点分配一个新的权值

不妨假设1号点的权值不变

1号点的儿子的权值为原来的权值乘上1号点儿子的个数.......以此类推。

发现权值相同的点在一个方案里

由于权值可能很大,我们随缘取模哈希一下就行

 

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
#define N 500050
int head
,to[N<<1],nxt[N<<1],val
,cnt;
int n,son
,dep
;
LL now
;
int h[1930010],p=1910009;
int ans,key[1930010];
inline void add(int u,int v)
{
to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void insert(LL x)
{
int k=(x%p+p)%p;
while(h[k]&&key[k]!=x)
{
k++;
}
h[k]++;key[k]=x;
ans=max(ans,h[k]);
}
void dfs(int x,int y)
{
int i;
for(i=head[x];i;i=nxt[i])
{
if(to[i]!=y)
{
son[x]++;
}
}
for(i=head[x];i;i=nxt[i])
{
if(to[i]!=y)
{
now[to[i]]=now[x]*son[x]%p;
insert(val[to[i]]*now[to[i]]%p);
dfs(to[i],x);
}
}
}
int main()
{
scanf("%d",&n);
int i,x,y;
for(i=1;i<=n;i++)
{
scanf("%d",&val[i]);
}
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
insert(val[1]);
now[1]=1;
dfs(1,0);
printf("%d\n",n-ans);
}

  

 

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: