欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

联合权值

程序员文章站 2022-05-22 14:35:08
...

读完题我们会发现此题有树结构。
我们以1为根结点。
假设我们已经做完了x号节点(x可以是叶子节点)的儿子们(y号节点),
我们就在x号节点的tot加上y的tot。
设maxx为与x连边的节点中点权最大值,
每次maxx与y的点权的乘积就可能是最大值。
设sum为与x连边的节点中点权之和,x的tot加上sum与y的点权的乘积,
这样就能不重复的统计所有序点对的联合权值。自己模拟一下就可以知道。
返回最大值(maxx)和tot

#include<cstdio>
#include<algorithm>
using namespace std;

const int p=10007,M=200010;
struct bian{int y,gg;}b[M<<1];
struct lol{int tot,maxx;};
int h[M],a[M],len=0;

void ins(int x,int y)
{
	b[++len].y=y;b[len].gg=h[x];
	h[x]=len;
}

lol dfs(int x,int fa)
{
	lol ans;
	int maxx,sum;
	sum=maxx=a[fa];
	ans.tot=ans.maxx=0;
	for(int i=h[x];i;i=b[i].gg)
	{
		int y=b[i].y;
		if(fa==y)continue;
		lol k=dfs(y,x);
		ans.maxx=max(ans.maxx,k.maxx);
		ans.tot=(ans.tot+k.tot)%p;
		ans.tot=(ans.tot+sum*a[y]%p)%p;
		sum=(sum+a[y])%p;
		
		ans.maxx=max(maxx*a[y],ans.maxx);
		maxx=max(a[y],maxx);	
	}

	return ans;
}

int main()
{
	int n;scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int x,y;scanf("%d %d",&x,&y);
		if(x>y){x^=y;y^=x;x^=y;}//swap
		ins(x,y);ins(y,x);
	}
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	lol ans=dfs(1,0);
	printf("%d %d",ans.maxx,(ans.tot<<1)%p);
	return 0;
}