P1351 联合权值

题目描述

无向连通图 G 有 n 个点,n−1 条边。点从 1 到 n 依次编号,编号为 i 的点的权值为 Wi,每条边的长度均为 1。图上两点 (u,v) 的距离定义为 u 点到 v 点的最短距离。对于图 G 上的点对 (u,v),若它们的距离为 2,则它们之间会产生Wv×Wu的联合权值。

请问图 G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?

输入格式

第一行包含 1 个整数 n。

接下来 n−1 行,每行包含 2 个用空格隔开的正整数 u,v,表示编号为 u 和编号为 v 的点之间有边相连。

最后 1 行,包含 n 个正整数,每两个正整数之间用一个空格隔开,其中第 i 个整数表示图 G 上编号为 i 的点的权值为 Wi。

输出格式

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

输入输出样例

输入 #1
5  
1 2  
2 3
3 4  
4 5  
1 5 2 3 10 
输出 #1
20 74

说明/提示

P1351 联合权值

本例输入的图如上所示,距离为2 的有序点对有(1,3) 、(2,4) 、(3,1) 、(3,5)、(4,2) 、(5,3)。

其联合权值分别为2 、15、2 、20、15、20。其中最大的是20,总和为74。

【数据说明】

对于30%的数据,1<n≤100;

对于60%的数据,1<n≤2000;

对于100%的数据,1<n≤200000,0<Wi≤10000。

保证一定存在可产生联合权值的有序点对。

思路

你枚举每一个点;

然后枚举可以连到他的点;

然后对着些点直接统计答案就好了

但菊花图就过不了了呢~

So,来自大神的题解

代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=200010;
const int Mod=10007;

struct cs {
	int to,nxt;
} a[N*2];

int head[N],tot,v[N];
int n,ans,x,y,maxans;

void add(int u,int v) {
	tot++;
	a[tot].to=v;
	a[tot].nxt=head[u];
	head[u]=tot;
}

void work(int x) {
	int sum=0,ma=0,m=0;
	for(int i=head[x]; i; i=a[i].nxt) {
		if(v[a[i].to]>ma) {
			m=ma;
			ma=v[a[i].to];
		} else if(v[a[i].to]>m)
			m=v[a[i].to];
		ans=(ans+sum*v[a[i].to])%Mod;
		sum=(sum+v[a[i].to])%Mod;
	}
	maxans=max(maxans,ma*m);
}

int main () {
	scanf("%d",&n);
	for(int i=1; i<n; i++) {
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	for(int i=1; i<=n; i++)
		scanf("%d",&v[i]);
	for(int i=1; i<=n; i++)
		work(i);
	printf("%d %d\n",maxans,(ans*2)%Mod);
	return 0;
}

 

上一篇:PAT甲级1011水题飘过


下一篇:线段树合并学习笔记(P4556)