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

联合权值(树上小操作)

程序员文章站 2022-03-03 11:34:00
...

题目描述

无向连通图 GGnn 个点,n1n-1 条边。点从 11nn 依次编号,编号为 ii 的点的权值为 WiW_i, 每条边的长度均为 11。图上两点(u,v)(u, v)的距离定义为 uu 点到 vv 点的最短距离。对于图 GG 上的点对(u,v)(u, v),若它们的距离为 22,则它们之间会产生WuW_u××WvW_v的联合权值。
请问图 G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?

输入格式

第一行包含11个整数 nn
接下来 n1n-1 行,每行包含 22 个用空格隔开的正整数 uvu、v,表示编号为 uu 和编号为 vv 的点 之间有边相连。
最后 11 行,包含 nn 个正整数,每两个正整数之间用一个空格隔开,其中第 ii 个整数表示 图 GG 上编号为 ii 的点的权值为WiW_i

输出格式

输出共 11 行,包含 22 个整数,之间用一个空格隔开,依次为图 GG 上联合权值的最大值 和所有联合权值之和。由于所有联合权值之和可能很大,输出它时要对 1000710007 取余。

样例输入

55
11 22
22 33
33 44
44 55
11 55 22 33 1010

样例输出

2020 7474

限制

对于 3030%的数据,1<n1001 < n ≤ 100
对于 6060%的数据,1<n20001 < n ≤ 2000
对于 100100%的数据,1<n200,0000<Wi10,0001 < n ≤ 200,000,0 < W_i ≤ 10,000

解析

原图就是一棵无根树啊。
树上u,vu,v两点间距离为22只有两种情况:

  • u,vu,v之间是祖父与孙子的关系
  • u,vu,v之间是兄弟的关系

因为一个节点至多有一个祖父节点,而有可能有多个孙子节点,所以我们可以找每个节点的祖父节点,并将和的答案乘22即可。
对于第二种情况我们只要统计每个节点权值最大和次大的儿子节点即可求出最大值。
S=vson[u]w[v]{S=\sum_{v∈son[u]} w[v]}
T=vson[u]w[v]2{T=\sum_{v∈son[u]} w[v]^2}
至于和,对于节点uu,它的儿子的权值和即为
S2TS^2-T
轻松解决此题。

代码

#include<cstdio>
using namespace std;
const int p = 10007;
const int maxn = 200005;
const int maxe = 200005;
int edgenum;
int Next[maxe << 1] , vet[maxe << 1] , head[maxn];
int fa[maxn] , mx[maxn] , cmx[maxn] , sum[maxn] , sqr_sum[maxn];
int w[maxn];
int max(int x , int y){return x > y ? x : y;}
int sqr(int x){return x * x;}
int read()
{
	char ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	int res = 0;
	while(ch >= '0' && ch <= '9') res = (res << 3) + (res << 1) + (ch ^ 48) , ch = getchar();
	return res;
}
void clear_edge(int n)
{
	edgenum = 0;
	for(int i = 1;i <= n;i++) head[i] = 0;
}
void add_edge(int u , int v)
{
	edgenum++;
	Next[edgenum] = head[u];
	vet[edgenum] = v;
	head[u] = edgenum;
}
void dfs(int u , int father)
{
	fa[u] = father;
	mx[u] = 0;
	cmx[u] = 0;
	sum[u] = 0;
	sqr_sum[u] = 0;
	for(int e = head[u];e;e = Next[e])
	{
		int v = vet[e];
		if(v == fa[u]) continue;
		dfs(v , u);
		if(w[v] > mx[u]) cmx[u] = mx[u] , mx[u] = w[v];
		else if(w[v] > cmx[u]) cmx[u] = w[v];
		sum[u] = (sum[u] + w[v]) % p;
		sqr_sum[u] = (sqr_sum[u] + sqr(w[v]) % p) % p;
	}
}
int main()
{
	freopen("link.in","r",stdin);
	freopen("link.out","w",stdout);
	int n = read();
	clear_edge(n);
	for(int i = 1;i < n;i++)
	{
		int u = read() , v = read();
		add_edge(u , v) , add_edge(v , u);
	}
	for(int i = 1;i <= n;i++) w[i] = read();
	dfs(1 , 0);
	int ans_max = 0 , ans_tot = 0;
	for(int i = 1;i <= n;i++)
		if(fa[fa[i]] != 0)
		{
			ans_max = max(ans_max , w[i] * w[fa[fa[i]]]);
			ans_tot = (ans_tot + w[i] * w[fa[fa[i]]] % p) % p;
		}
	ans_tot = (ans_tot << 1) % p;
	for(int i = 1;i <= n;i++)
	{
		ans_max = max(ans_max , mx[i] * cmx[i]);
		ans_tot = (ans_tot + sqr(sum[i]) % p - sqr_sum[i] + p) % p;
	}
	printf("%d %d\n",ans_max,ans_tot);
	return 0;
}
相关标签: 图论