Description
给定n点n-1条边的连通图和各点的权值,统计所有距离为2的两点权值乘积之和与最大乘积
Solution
题意让我想起了幂萎的敌敌
首先要想到题目给的是一棵树,那么就相当于对所有相邻节点的权积求和
dfs的过程中枚举节点求积是会T的,于是考虑O(n)的方法。
已知
(a+b+c)2=a2+b2+c2+2ab+2ac+2bc
,
那么不难得到
2(a+b+c)=(a+b+c)2−a2+b2+c2
显然可以记录一下搞出来
洛谷a了但是学校题库不行(汗,拿着幂萎的标就交了
Code
#include <stdio.h>
#include <vector>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define erg(i, now) for (int i = ls[now]; i; i = e[i].next)
#define fill(x, t) memset(x, t, sizeof(x))
#define ll long long
#define pb push_back
#define MOD 10007
#define N 400001
#define E N * 4 + 1
#define L 30
using namespace std;
struct edge{int x, y, w, next;}e[E];
ll w[N], tot = 0, mx = 0;
int ls[N], d[N];
inline void addEdge(int &cnt, int x, int y, int w = 1){
e[++ cnt] = (edge){x, y, w, ls[x]}; ls[x] = cnt;
}
inline ll max(ll x, ll y){
return x > y ? x: y;
}
inline void dfs1(int now, int dep){
d[now] = dep;
erg(i, now){
if (!d[e[i].y]){
dfs1(e[i].y, dep + 1);
}
}
vector<ll> v;
erg(i, now){
v.pb(e[i].y);
}
if (v.size()){
ll sum = 0, sqs = 0;
ll m1 = 0, m2;
rep(i, 0, v.size() - 1){
if (w[v[i]] > m1){
m2 = m1;
m1 = w[v[i]];
}else if (w[v[i]] > m2){
m2 = w[v[i]];
}
sum = (sum + w[v[i]]) % MOD;
sqs = (sqs + w[v[i]] * w[v[i]] % MOD) % MOD;
}
ll ret = (sum * sum % MOD + MOD - sqs) % MOD;
tot = (ret + tot) % MOD;
mx = max(mx, m1 * m2);
}
}
int main(void){
int n;
scanf("%d", &n);
int edgeCnt = 0;
rep(i, 1, n - 1){
int x, y;
scanf("%d%d", &x, &y);
addEdge(edgeCnt, x, y);
addEdge(edgeCnt, y, x);
}
rep(i, 1, n){
scanf("%lld", &w[i]);
}
dfs1(1, 1);
printf("%d %lld\n", mx, tot);
return 0;
}