洛谷P1351 联合权值

(Large extbf{Description:}) (large一棵树,父子之间距离为1,求距离为2的两点点权之积的最大值与和。)

(Large extbf{Solution:})(large考虑到边权为1,那么距离为2的两点可能问爷爷与孙子的关系,或者为兄弟的关系。那么对于一个点,它对答案的贡献是它所有孙子的点权之和与它的点权的积加上它与所有兄弟的有兄弟的点权的积。那么我们只需遍历一遍树即可,时间复杂度O(n)。)

(Large extbf{Code:})

#include <cstdio>
#include <algorithm>
#include <iostream>
#define LL long long
#define gc() getchar()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 2e5 + 5;
const int Mod = 10007;
int n, m, cnt, a[N], head[N];
LL ans, Max, sum[N];

struct Edge {
	int to, next;	
}e[N << 1];

struct Node {
	LL su, max12; //开一个结构体 存储其孙子的点权之和与点权最大值。
	Node() {
		su = max12 = 0;
	}
};

inline int read() {
	char ch = gc();
	int ans = 0, flag = 1;
	while (ch > '9' || ch < '0') {
		if (ch == '-') flag = -1;
		ch = gc();
	}
	while (ch >= '0' && ch <= '9') ans = (ans << 1) + (ans << 3) + ch - '0', ch = gc();
	return ans * flag;
}

inline void add(int l, int r) {
	e[++cnt].to = r;
	e[cnt].next = head[l];
	head[l] = cnt;
}

inline LL max(LL x, LL y) {
	return x >= y ? x : y;
}

inline Node dfs(int now, int fa) {
	Node q, x;
	LL an = 0, s = 0;
	LL max1 = 0, max2 = 0;
	for (int i = head[now]; i ; i = e[i].next) {
		int u = e[i].to;
		if (u != fa) {
			an = an + a[u];
			ans = (ans + sum[now] * a[u] % Mod) % Mod;
			sum[now] = (sum[now] + a[u]) % Mod;
			x = dfs(u, now);
			s = s + x.su;
			q.max12 = max(q.max12, a[u]);
			if (a[u] > max1) max2 = max1, max1 = a[u];
			else if (a[u] > max2) max2 = a[u];
		}
		else continue;
	}
	if (max2) Max = max(Max, max1 * max2);
	Max = max(Max, x.max12 * a[now]);
	ans = (ans + s * a[now] % Mod) % Mod;
	q.su = an;
	return q;
}

int main() {
	n = read();
	int l, r;
	rep(i, 2, n) l = read(), r = read(), add(l, r), add(r, l);
	rep(i, 1, n) a[i] = read();
	dfs(1, 0);
	ans = (ans << 1) % Mod;
	printf("%lld %lld
", Max, ans);
	return 0;
}

(Largecolor{pink}{by}) (Largecolor{pink}{Miraclys})

原文地址:https://www.cnblogs.com/Miraclys/p/12261942.html