题目描述
某天,好吃的QQ被火星人莫名其妙的传送到了树形国的首都root,正如其名,树形国就是一棵树,一共n个城市,有n-1条路连接,城市与城市之间都连通
令人吃惊的是,QQ不知道用什么方法,得知了树形国各个城市的小吃种类(可以认为任意两个小吃都是不同种类的),于是乎他想一边游玩树形国,一边品尝各种的小吃,而QQ从一个城市s,走到相邻的一个城市t,当且仅当城市t存在一种他没有吃过的小吃,而他到城市t之后就会立即品尝那一种小吃,却不会品尝该城市其他的小吃
那么,请你为好吃的QQ设计一个路线,使得他能品尝到尽量多种类的小吃,并且最后会回到首都root,以便火星人送他回家
输入格式
第一行一个数n,表示树形国的城市数
第二行n个数表示每个城市的小吃种类
以下n-1行,每行2个数a,b,表示有一条路连接城市a,b
接下来一行一个数root,表示树形国的首都
输出格式
一个数表示QQ最多能吃到多少种小吃
样例
样例输入
5
2 1 1 1 1
1 2
2 3
1 4
4 5
1
样例输出
4
数据范围与提示
【友情提示】
一开始被传送到首都时,QQ并不会品尝首都的小吃,请注意最后要回到首都root
样例路线start>1>2(+)>1(+)>4(+)>1(+)>end
【数据约定】
设t为max{每个城市的小吃种类}
30%数据满足n≤5,t≤5
60%数据满足n≤30,t≤30
100%数据满足n≤100000,0≤t≤2^31
来源
长郡Noip2014模拟1
题解:
树形DP
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100005
using namespace std;
long long f[N],res[N],up[N];
int n,root,head[N],ver[N<<1],nex[N<<1],tot,fa[N],cnt[N];
struct node
{
int ff;
}temp[N];
bool cmp(node a,node b){
return a.ff>b.ff;
}
inline void add(int x,int y){
nex[++tot]=head[x];
head[x]=tot;
ver[tot]=y;
}
void tree_dfs(int x){
up[x]-=1;
if(x!=root&&up[x]>=0)f[x]+=1;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(fa[x]==y)continue;
fa[y]=x;
tree_dfs(y);
}long long now=0;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(fa[x]==y)continue;
temp[++cnt[x]].ff=f[y];
now=now+res[y];
}
sort(temp+1,temp+1+cnt[x],cmp);
for(int i=1;i<=cnt[x];++i){
if(up[x]<=0)break;
if(temp[i].ff<=0)break;
f[x]=f[x]+temp[i].ff+1;up[x]-=1;
}
f[x]+=2*max((long long)0,min(now,up[x]));
res[x]=max((long long)0,up[x]-now);
//cout<<x<<" "<<f[x]<<" "<<res[x]<<endl;
}
int main()
{
//freopen("eat.in","r",stdin);
//freopen("eat.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%lld",&up[i]);
for(int i=1;i<n;++i){
int x,y;scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
cin>>root;
fa[root]=-1;up[root]+=1;
tree_dfs(root);
//fa[4]=1;
//tree_dfs(4);
// for(int i=1;i<=n;i++)cout<<up[i]<<endl;
cout<<f[root]<<endl;
return 0;
}
/*
4
0 3 2 0
2 3
1 2
4 1
2
*/