码迷,mamicode.com
首页 > 其他好文 > 详细

[NOIP2014]联合权值

时间:2016-04-02 22:57:53      阅读:400      评论:0      收藏:0      [点我收藏+]

标签:

描述

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

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

输入格式

输入文件名为link.in。

第一行包含1个整数n。

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

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

输入样例:

5

1 2

2 3

3 4

4 5

1 5 2 3 10

输出格式

输出文件名为link.out。

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

输出样例:

20 74

备注

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

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

对于100%的数据,1<n≤200,000,0<Wi ≤10,000。


分析

一开始用纯暴力方法过了7个点。后来看网上一些题解,又仔细看了一遍题目,大致明白方法了。

由于产生联合权值的两点最短距离为2,所以可以认为这两个两个点由一个中转点连接。那么直接保存每个点的邻点,在这些邻点里两两配对就可以了。但两两配对显然太慢,计算每一个中转点邻点的联合权值都要O(k2)的计算(k为邻点个数)。这样显然是不划算的。网上有介绍了利用加法结合律(没错加法结合律)的优化:预处理出每个点i的邻点的权值总和S[i],那么总联合权值和SUM=sum{ sum{W[V[i][j]] * (S[i] - W[V[i][j]])} (0≤j≤k) } (1≤i≤n)。

而最大权值可以在计算S[i]的时候直接找到i邻点中最大的两个相乘找到。

tyvj上可以直接AC,vijos需要用getint优化读入。

代码

 1 #include <cstdio>
 2 #include <cctype>
 3 #include <vector>
 4 using namespace std;
 5 vector<int> V[200001];
 6 int S[200001];
 7 int W[200001];
 8 int n, maxx, sum;
 9 int getint()
10 {
11     char c = getchar();
12     while (!isdigit(c))
13         c = getchar();
14     int x = 0;
15     while (isdigit(c)) {
16         x = x * 10 + c - 0;
17         c = getchar();
18     }
19     return x;
20 }
21 void add(int i)
22 {
23     for (int j = 0; j != V[i].size(); ++j)
24         sum = (sum + (S[i] - W[V[i][j]]) * W[V[i][j]]) % 10007;
25 }
26 int main()
27 {
28     n = getint();
29     for (int i = 0, a, b; i != n - 1; ++i) {
30         a = getint();
31         b = getint();
32         V[a].push_back(b);
33         V[b].push_back(a);
34     }
35     for (int i = 1; i <= n; ++i)
36         W[i] = getint();
37     for (int i = 1; i <= n; ++i) {
38         int max1, max2;
39         max1 = 0;
40         max2 = 0;
41         for (int j = 0; j != V[i].size(); ++j) {
42             S[i] += W[V[i][j]];
43             if (S[i] > 10007)
44                 S[i] -= 10007;
45             if (W[V[i][j]] > max1) {
46                 max2 = max1;
47                 max1 = W[V[i][j]];
48             }
49             else if (W[V[i][j]] == max1 || W[V[i][j]] > max2)
50                 max2 = W[V[i][j]];
51         }
52         if (max1 * max2 > maxx)
53             maxx = max1 * max2;
54     }
55     for (int i = 1; i <= n; ++i)
56         add(i);
57     printf("%d\40%d", maxx, sum % 10007);
58     return 0;
59 }

 

[NOIP2014]联合权值

标签:

原文地址:http://www.cnblogs.com/smileandyxu/p/5348411.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!