BZOJ3872 : [Poi2014]Ant colony

设i点的度数为d[i]

则如果有x只蚂蚁在从i走到别处,会分裂成每群$\lfloor\frac{x}{d[i]-1}\rfloor$只蚂蚁

对于x出发的m只蚂蚁,到y处还剩$\lfloor\frac{m}{x到y路径上所有点度数-1的乘积}\rfloor$

于是我们一遍DFS求出到每个叶子节点时一路上点度数-1的乘积,再在数组中二分查找出一个合法的区间即可

 

#include<cstdio>

#include<algorithm>

#define N 1000010

typedef long long ll;

int n,m,k,i,j,x,y,g[N],nxt[N<<1],v[N<<1],d[N],ed,a[N];ll ans;

inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}

inline void add(int x,int y){d[x]++;v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}

inline int ask(ll x){

  if(x>a[m])return m;

  if(x<=a[1])return 0;

  int l=1,r=m,t,mid;

  while(l<=r)if(a[mid=(l+r)>>1]<x)l=(t=mid)+1;else r=mid-1;

  return t;

}

void dfs(int x,int y,int t){

  if(!d[x])ans+=ask((ll)(k+1)*t)-ask((ll)k*t);

  if((ll)t*d[x]>a[m])return;t*=d[x];

  for(int i=g[x];i;i=nxt[i])if(i>2&&v[i]!=y)dfs(v[i],x,t);

}

int main(){

  read(n),read(m),read(k);

  for(i=1;i<=m;i++)read(a[i]);

  std::sort(a+1,a+m+1);

  for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);

  for(i=1;i<=n;i++)d[i]--;

  dfs(v[1],0,1);dfs(v[2],0,1);

  return printf("%lld",ans*k),0;

}

  

 

你可能感兴趣的:(ant)