hdu3899树中选择开会地点(树,树形DP) 多校六1010

防爆栈,只要在头文件的前面加上#pragma comment(linker, "/STACK:102400000,102400000")就可以了
/*题意:给一树,每个结点有人数,边有权值,表示经过这条边所需时间,
问取某个结点作为开会地点,所有人全部到达此结点最少所需总时间?

分析:先深搜一次,把以每个结点为根结点的子树的结点数目以及
子树中所有结点到此结点的时间和求出来。然后再利用上面所求的信息,
再深搜一次。对于当前某结点作为最终开会的地点,总时间可分为三种,
第一种是所有父亲结点及以上的点到父亲结点的时间和
第二种是此结点的子树中的结点到此结点的时间和
第三种是父亲及以上的结点与此结点的兄弟结点到此结点的时间和
因为结点太多,直接深搜爆栈,所以要手动模拟。注释部分为直接深搜
*/
#include<stdio.h>
#include<vector>
#include<iostream>
using namespace std;

const __int64 maxn=110000;
__int64 n,minsum,q[maxn],p[maxn],f[maxn],sump[maxn],sum[maxn],sump2[maxn],sum2[maxn];
bool flag[maxn];

struct point
{
	__int64 v,w;
}p0;
vector<point>e[maxn];
void DFS1()
{
	__int64 i,j,k,top=0;
	memset(flag,false,sizeof(flag));
	q[top++]=1;
	while(top)
	{
		k=q[top-1];
		if(!flag[k])
		{
			flag[k]=true;
			for(i=0;i<e[k].size();i++)
			{
				j=e[k][i].v;
				if(j==f[k]) continue;
				f[j]=k;
				q[top++]=j;
			}
		}
		else
		{
			sump[k]=p[k];
			for(i=0;i<e[k].size();i++)
			{
				j=e[k][i].v;
				if(j==f[k]) continue;
				sump[k]+=sump[j];
				sum[k]+=sum[j]+sump[j]*e[k][i].w;
			}
			top--;
		}
	}



/*	sump[now]=p[now];
	for(i=0;i<e[now].size();i++)
	{
		j=e[now][i].v;
		if(j==f) continue;
		DFS1(j,now);
		sump[now]+=sump[j];//子代结点数目
		sum[now]+=sump[j]*e[now][i].w+sum[j];//子代到其时间和
	}*/
}
void DFS2()//void DFS2(int now,int f,int sum1,int p1)表示现在在now结点,其父亲为f,除了其父亲为根结点的树中的点到其父亲的的总时间和总结点数
{
	__int64 now,i,j,top=0;
	memset(flag,false,sizeof(flag));
	q[top++]=1;
	if(sum[1]<minsum) minsum=sum[1];
	while(top)
	{
		now=q[top-1];
		if(!flag[now])
		{
			flag[now]=true;
			for(i=0;i<e[now].size();i++)
			{
				j=e[now][i].v;
				if(j==f[now]) continue;
				f[j]=now;
				sump2[j]=sump2[now]+sump[now]-sump[j];
				sum2[j]=sum2[now]+sum[now]-sum[j]-sump[j]*e[now][i].w+sump2[j]*e[now][i].w;
				if(sum[j]+sum2[j]<minsum) minsum=sum[j]+sum2[j];
				q[top++]=j;
			}
		}
		else top--;
	}
	/*i=sum[now]+sum1;
	if(i<minsum) minsum=i;
	for(i=0;i<e[now].size();i++)
	{
		j=e[now][i].v;
		if(j==f)continue;
		DFS2(j,now,sum1+sum[now]-sum[j]-sump[j]*e[now][i].w+(p1+sump[now]-sump[j])*e[now][i].w,p1+sum[now]-sump[j]);
	}*/
}
__int64 main()
{
	__int64 i,u,v,w;
	while(scanf("%I64d",&n)!=EOF)
	{
		for(i=1;i<=n;i++)
			scanf("%I64d",&p[i]);
		for(i=0;i<=n;i++)
			e[i].clear();
		for(i=1;i<n;i++)
		{
			scanf("%I64d%I64d%I64d",&u,&v,&w);
			p0.v=v,p0.w=w;
			e[u].push_back(p0);
			p0.v=u;
			e[v].push_back(p0);
		}

		memset(f,-1,sizeof(f));
		memset(sump,0,sizeof(sump));
		memset(sum,0,sizeof(sum));
		minsum=0x7fffffffffffffff;
		DFS1();

		memset(sum2,0,sizeof(sum2));
		memset(sump2,0,sizeof(sump2));
		DFS2();
		printf("%I64d\n",minsum);
	}
	return 0;
}

 

你可能感兴趣的:(hdu3899树中选择开会地点(树,树形DP) 多校六1010)