[ HNOI 2014 ] 米特运输

\(\\\)

\(Description\)


给出一棵有根树,其中 \(1\) 号点是根节点,深度为 \(1\) 。每个点又有一个储存器,有各自的容量上限。

每天 \(1\) 号点的储存器先清空,所有叶子节点全部充满能量。

然后,深度为 \(2\) 的节点把 所有 储存的能量全部给根节点,然后,深度为 \(3\) 的节点把 所有 储存的能量给父节点,依次往下。

运输过程中有几个要求:

  • 不能把父节点装入的能量超过限制,否则父节点爆炸
  • 必须把自己的所有能量给父节点
  • 每个节点的孩子给父亲的能量必须等量
  • 在每一层的传输完成后,父节点的那一层所存能量必须正好等于上界

求把整个树形结构修改到满足上面的要求,最少需要修改多少个节点的容量上限。

  • \(N\le5\times 10^5\)

\(\\\)

\(Solution\)


好一道语文题......

总的限制其实就一个,要求调整后满足,对于每个节点,其容量上限等于子节点容量上限之和,且每个子节点容量上限相等。

这道题的思路需要手玩.....

\(\\\)

我们发现整颗树每一个节点的最终容量确定,只需要确定树中的任意一个节点的容量。

因为节点之间的容量关系满足\((cnt[x]\) 表示节点 \(x\) 的子节点个数\()\)

\[size[fa]=size[son]\times cnt[fa]\ ,\ size[son]=\frac{size[fa]}{cnt[fa]} \]

显然确定一个点就能确定整棵树,同样的,我们也能得出一个结论,只要有一个节点容量相同,方案就相同

\(\\\)

然后考虑如何快速表示出相同的方案,显然可以用同一个节点在这一方案里要求的权值表示,不妨选取根节点。

然后我们的任务就是统计出每一个节点在容量上限不变的前提下,根节点的容量上限要变成什么。

显然我们不再需要考虑子树内的点了,对于节点 \(x\) ,它不变的前提下根节点的容量就是

\[size[x]\times cnt[fa[x]]\times cnt[fa[fa[x]]]\times....\times cnt[root] \]

这个后缀我们可以在 \(DFS\) 的时候记录,根节点到当前节点路径上所有点的计数器之积。

但是这个东西太大了,不太好记录,我们考虑 \(Hash\) 一下。其实还有更妙的方法。

\(\\\)

我们知道对于对数有一个恒等式

\[log\ (A\times B\times...\times C)=log\ A+ log\ B+\ ...+\ log\ C \]

然后我们可以通过取对数的方式来缩小数据范围,这样我们在 \(DFS\) 的时候只需要记录路径计数器取对数之和。

然后将得到的答案排序,数字相同即是一个方案,代表在这个方案下这些点都不需要修改。

统计最多的相同的数字有多少个,答案就是用 \(N\) 减掉它。

\(\\\)

\(Code\)


#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 500010
#define R register
#define gc getchar
using namespace std;

double ans[N];

int n,m,tot,res,hd[N],val[N],cnt[N];

struct edge{int to,nxt;}e[N<<1];

inline void add(int u,int v){
  e[++tot].to=v; e[tot].nxt=hd[u]; hd[u]=tot;
}

void dfs1(int u,int fa){
  for(R int i=hd[u],v;i;i=e[i].nxt)
    if((v=e[i].to)!=fa){++cnt[u];dfs1(v,u);}
}

inline void dfs2(int u,int fa){
  for(R int i=hd[u],v;i;i=e[i].nxt)
    if((v=e[i].to)!=fa){ans[v]=ans[u]+log((double)cnt[u]);dfs2(v,u);}
}

inline int rd(){
  int x=0; bool f=0; char c=gc();
  while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  return f?-x:x;
}

int main(){
  n=rd();
  for(R int i=1;i<=n;++i) val[i]=rd();
  for(R int i=1,u,v;i<n;++i){
    u=rd(); v=rd(); add(u,v); add(v,u);
  }
  dfs1(1,0); ans[1]=log(1.0); dfs2(1,0);
  for(R int i=1;i<=n;++i) ans[i]+=log((double)val[i]);
  sort(ans+1,ans+1+n);
  for(R int i=1,tmp;i<=n;++i){
    tmp=1;
    while(fabs(ans[i+1]-ans[i])<=1e-8) ++tmp,++i;
    res=max(res,tmp);
  }
  printf("%d\n",n-res);
  return 0;
}

posted @ 2018-10-18 16:47  SGCollin  阅读(93)  评论(0编辑  收藏  举报