Codeforces Beta Round #69 (Div. 2 Only) E树型DP 一树,每个结点有虫子,一次只能吃一只,不能停留,问从根结点出发再回到根结点最多能吃多少只虫子

 
/*
题意:一树,每个结点有虫子,一次只能吃一只,
不能停留,问从根结点出发再回到根结点最多能吃多少只虫子
思想:记录从某个结点出发再回到该结点最多能吃的虫子,然后
      由将子结点按能吃的虫子数排序,选择。注意可能多次下去。
*/
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int maxn=110000;
const int maxm=210000;
struct edge
{
	int u,v,next;
}e[maxm];
int num,edgeNum,p[maxn],first[maxn];
__int64 a[maxn];
void Addedge(int u,int v)
{
	e[edgeNum].u=u,e[edgeNum].v=v,e[edgeNum].next=first[u],first[u]=edgeNum++;
	e[edgeNum].u=v,e[edgeNum].v=u,e[edgeNum].next=first[v],first[v]=edgeNum++;
}

__int64 DFS(int t,int f,int &left)
{
	int i,j=num,k,ii,jj=0;
	__int64 sum=1;//从根结点到此结点要吃一个
	for(k=first[t];k!=-1;k=e[k].next)
	{
		if(e[k].v==f) continue;
		a[num++]=DFS(e[k].v,t,ii);
		jj+=ii;//以e[k].v为根结点时,它还剩多少虫子
	}
	sort(a+j,a+num);
	for(i=num-1;i>num-1-p[t]&&i>=j;i--)
		sum+=a[i]+1;//下去吃a[i],回来此结点再吃一个
	if(p[t]>num-j)//还要再下去
	{
		if(p[t]-num+j>=jj)
		{
			sum+=2*jj;
			left=p[t]-num+j-jj;
		}
		else
		{
			sum+=2*(p[t]-num+j);
			left=0;
		}
	}
	else left=0;
	num=j;
	return sum;
}
int main()
{
	int n,u,v,i,j;
	while(scanf("%d",&n)!=EOF)
	{
		for(i=1;i<=n;i++)
		{
			scanf("%d",&p[i]);
			p[i]--;
		}
		memset(first,-1,sizeof(first));
		for(edgeNum=0,i=1;i<n;i++)
		{
			scanf("%d%d",&u,&v);
			Addedge(u,v);
		}
		scanf("%d",&u);
		p[u]++;
		num=0;
		printf("%I64d\n",DFS(u,-1,i)-1);
	}
    return 0;
}

你可能感兴趣的:(Codeforces Beta Round #69 (Div. 2 Only) E树型DP 一树,每个结点有虫子,一次只能吃一只,不能停留,问从根结点出发再回到根结点最多能吃多少只虫子)