Problem
record
Solution
(60 ext{ or } 70 ext{pts})
直接爆搜,枚举每两个距离为 2 的点,然后记录答案。
写法优异可以拿走 (70 ext{pts}) , 但是 use-v4
几乎铁定是 (60 ext{pts}) 。
代码。。。就不放了,有兴趣的可以看:
(60 ext{pts}) (
use-v4
)
(70 ext{pts}) (
use-v3
)
$ 70Rightarrow 100 ext{pts}$
考虑我们的思路慢在哪儿?
在于组合!
考虑一个菊花图,复杂度几乎是 (Θ(n^2)) 的,当然慢。
想到乘法交换律(数学老师不要怪我这么长时间才想起你)
这时候考虑任意两个距离为 2 的有序点对一定会有一个中间点,枚举这个点即可,并不需要搜索。复杂度 (Θ(n)) ,菊花图不会卡
(100 ext{pts})
思路基本没什么问题了吧!
等等,图 G 上联合权值的最大值呢?
每次记录中间点相邻点中最大的和次大的即可。
没问题了吧?
不,还有问题!
答案要乘 2 !
因为题目可以看成一对有序点对要计算两次。
Code
// luogu-judger-enable-o2
/*
Problem: P1351 联合权值
Author: 航空信奥
Date: 2018/08/18
Upload: Luogu
P.s.: use-v4
*/
#pragma GCC optimize("O1")
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
namespace AuthorName { /* 防重名 */
template <typename _TpInt> inline _TpInt read();
template <typename _TpInt> inline void write(_TpInt x);
# define Online_Judge
# define Max_N 200007
# define Mod 10007
vector<vector<int> > g;
int *w;
int maxx = 0, sum = 0;
void work(int p)
{
int max_1st = 0, max_2nd = 0, temp_sum = 0;
for (size_t i = 0; i < g[p].size(); i++) {
if (w[g[p][i]] > max_1st) {
max_2nd = max_1st;
max_1st = w[g[p][i]];
}
else if (w[g[p][i]] > max_2nd) {
max_2nd = w[g[p][i]];
}
sum = (sum + temp_sum * w[g[p][i]]) % Mod;
temp_sum = (temp_sum + w[g[p][i]]) % Mod;
}
maxx = max(maxx, max_1st * max_2nd);
}
int main()
{
int n;
n = read<int>();
g.resize(n + 1);
w = new int[n + 1];
int u, v;
for (int i = 1; i < n; i++) {
u = read<int>();
v = read<int>();
g[u].push_back(v);
g[v].push_back(u);
}
for (int i = 1; i <= n; i++) {
w[i] = read<int>();
}
for (int i = 1; i <= n; i++) {
work(i);
}
write(maxx), putchar(32), write((sum << 1) % Mod), putchar(10);
return 0;
}
#ifdef Online_Judge
char BufferRead[1 << 15];
int rLen = 0, rPos = 0;
inline char Getchar()
{
if (rPos == rLen) rPos = 0, rLen = fread(BufferRead, 1, 1 << 15, stdin);
if (rPos == rLen) return EOF;
return BufferRead[rPos++];
}
#else
# define Getchar() getchar()
#endif
template <typename _TpInt>
inline _TpInt read()
{
register int flag = 1;
register char c = Getchar();
while ((c > '9' || c < '0') && c != '-')
c = Getchar();
if (c == '-') flag = -1, c = Getchar();
register _TpInt init = (c & 15);
while ((c = Getchar()) <= '9' && c >= '0')
init = (init << 3) + (init << 1) + (c & 15);
return init * flag;
}
template <typename _TpInt>
inline void write(_TpInt x)
{
if (x < 0) {
putchar('-');
write<_TpInt>(~x + 1);
}
else {
if (x > 9) write<_TpInt>(x / 10);
putchar(x % 10 + '0');
}
}
}
int main()
{
AuthorName::main();
return 0;
}