[NOIP2014 提高组] 联合权值 dfs+技巧
题意
树上每个结点的权值为,若点和点满足:和的最短距离为2,则会产生的联合权值。
求最大联合权值和联合权值之和。
分析
①最大联合权值
对于结点,的叶节点之间一定能产生联合权值。
那么与相连的所有点之间都能产生联合权值。
的最大联合权值就是所有相连点中的最大值*次大值。
总的最大联合权值就是所有结点最大联合权值的最大值。
②联合权值之和
点集产生的联合权值之和为:
只需维护和与平方和即可。
代码
#include<iostream>
#include<cstdio>
const int maxn = 200000 + 10;
const int mod = 10007;
int nxt[maxn << 1], to[maxn << 1], head[maxn << 1], val[maxn << 1], cnt;
int max1[maxn << 1], max2[maxn << 1];//最大值及次大值
int sum[maxn << 1], sum2[maxn << 1];//和及平方和
int Max, Sum;//最大联合权值
int n, x, y;
inline void add(int a, int b) {
to[++cnt] = b;
nxt[cnt] = head[a];
head[a] = cnt;
}
inline void dfs1(int u, int fa) {
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
sum[u] = (sum[u] + val[v]) % mod;
sum2[u] = (sum2[u] + (val[v] * val[v] % mod)) % mod;
if (v == fa) continue;
dfs1(v, u);
}
}
inline void dfs2(int u, int fa) {
max1[u] = val[fa];
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (v == fa) continue;
if (val[v] >= max1[u]) max2[u] = max1[u], max1[u] = val[v];
if (val[v] < max1[u]) {
if (val[v] > max2[u]) max2[u] = val[v];
}
dfs2(v, u);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n - 1; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &val[i]);
}
dfs1(1, 0);
dfs2(1, 0);
for (int i = 1; i <= n; i++) {
Sum = (Sum + (sum[i] * sum[i] - sum2[i]) % mod) % mod;
Max = std::max(Max, (max1[i] * max2[i]));
}
printf("%d %d", Max, Sum);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!