您好,欢迎来到年旅网。
搜索
您的当前位置:首页联合权值(树上小操作)

联合权值(树上小操作)

来源:年旅网

输入格式

第一行包含 1 1 1个整数 n n n
接下来 n − 1 n-1 n1 行,每行包含 2 2 2 个用空格隔开的正整数 u 、 v u、v uv,表示编号为 u u u 和编号为 v v v 的点 之间有边相连。
最后 1 1 1 行,包含 n n n 个正整数,每两个正整数之间用一个空格隔开,其中第 i i i 个整数表示 图 G G G 上编号为 i i i 的点的权值为 W i W_i Wi

输出格式

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

样例输入

5 5 5
1 1 1 2 2 2
2 2 2 3 3 3
3 3 3 4 4 4
4 4 4 5 5 5
1 1 1 5 5 5 2 2 2 3 3 3 10 10 10

样例输出

20 20 20 74 74 74

对于 30 30 30%的数据, 1 &lt; n ≤ 100 1 &lt; n ≤ 100 1<n100
对于 60 60 60%的数据, 1 &lt; n ≤ 2000 1 &lt; n ≤ 2000 1<n2000
对于 100 100 100%的数据, 1 &lt; n ≤ 200 , 000 , 0 &lt; W i ≤ 10 , 000 1 &lt; n ≤ 200,000,0 &lt; W_i ≤ 10,000 1<n200,0000<Wi10,000

解析

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

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

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

代码

#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;
}

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- oldu.cn 版权所有 浙ICP备2024123271号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务