1. 程式人生 > >【BZOJ3872】[Poi2014]Ant colony 樹形DP+二分

【BZOJ3872】[Poi2014]Ant colony 樹形DP+二分

pro 數組 通過 main ram ret dot getc style

【BZOJ3872】[Poi2014]Ant colony

Description

給定一棵有n個節點的樹。在每個葉子節點,有g群螞蟻要從外面進來,其中第i群有m[i]只螞蟻。這些螞蟻會相繼進入樹中,而且要保證每一時刻每個節點最多只有一群螞蟻。這些螞蟻會按以下方式前進: ·在即將離開某個度數為d+1的點時,該群螞蟻有d個方向還沒有走過,這群螞蟻就會分裂成d群,每群數量都相等。如果d=0,那麽螞蟻會離開這棵樹。 ·如果螞蟻不能等分,那麽螞蟻之間會互相吞噬,直到可以等分為止,即一群螞蟻有m只,要分成d組,每組將會有floor(m/d)只,如下圖。 技術分享
一只饑餓的食蟻獸埋伏在一條邊上,如果有一群螞蟻通過這條邊,並且數量恰為k只,它就會吞掉這群螞蟻。請計算一共有多少只螞蟻會被吞掉。

Input

第一行包含三個整數n,g,k,表示點數、螞蟻群數以及k。 第二行包含g個整數m[1],m[2],...,m[g],表示每群螞蟻中螞蟻的數量。 接下來n-1行每行兩個整數,表示一條邊,食蟻獸埋伏在輸入的第一條邊上。

Output

Your program should print to the standard output a single line containing a single integer: the number of ants eaten by the anteater. 一個整數,即食蟻獸能吃掉的螞蟻的數量。

Sample Input

7 5 3
3 4 1 9 11
1 2
1 4
4 3
4 5
4 6
6 7

Sample Output

21

題解:可以先把第一條邊拆掉,然後分成兩棵樹進行樹形DP。因為根節點的取值是確定的,並且每個點的度數也是確定的,所以可以根據父親的取值範圍得出兒子的取值範圍,最終得出所有葉子節點的取值範圍。然後將m數組排序,對於每個節點都在m數組裏二分一下統計答案即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1000010;
const ll inf=1<<30;
int n,m,cnt,r1,r2;
ll K,ans;
int to[maxn<<1],next[maxn<<1],head[maxn],d[maxn],fa[maxn];
ll l[maxn],r[maxn],v[maxn];
inline void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void dfs(int x)
{
	for(int i=head[x];i!=-1;i=next[i])	if(to[i]!=fa[x])
	{
		fa[to[i]]=x;
		if(d[to[i]]==1)	l[to[i]]=l[x],r[to[i]]=r[x];
		else	l[to[i]]=min(inf,l[x]*(d[to[i]]-1)),r[to[i]]=min(inf,(r[x]+1)*(d[to[i]]-1)-1);
		dfs(to[i]);
	}
}
int main()
{
	n=rd(),m=rd(),K=rd();
	int i,a,b;
	for(i=1;i<=m;i++)	v[i]=rd();
	v[m+1]=inf+1;
	sort(v+1,v+m+1);
	r1=rd(),r2=rd(),d[r1]++,d[r2]++;
	memset(head,-1,sizeof(head));
	for(i=1;i<n-1;i++)	a=rd(),b=rd(),add(a,b),add(b,a),d[a]++,d[b]++;
	if(d[r1]==1)	l[r1]=r[r1]=K;
	else	l[r1]=K*(d[r1]-1),r[r1]=(K+1)*(d[r1]-1)-1;
	if(d[r2]==1)	l[r2]=r[r2]=K;
	else	l[r2]=K*(d[r2]-1),r[r2]=(K+1)*(d[r2]-1)-1;
	dfs(r1),dfs(r2);
	for(i=1;i<=n;i++)	if(d[i]==1)
		a=lower_bound(v+1,v+m+1,l[i])-v,b=upper_bound(v+1,v+m+1,r[i])-v,ans+=(b-a)*K;
	printf("%lld",ans);
	return 0;
}

【BZOJ3872】[Poi2014]Ant colony 樹形DP+二分