【NOIP2014】联合权值
本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P1351
还是挺简单的,一看n个点,n-1条边,就知道是树,所以建一下树。联合权值要求两个点之间距离为2,而每条边的长度均为1,所以共有两种情况,其中一个点是另一个点的父亲的父亲;两个点父亲相同。
所以我们可以求出每个结点儿子的权值之和,及其权值最大值和次大值,之所以要求次大值,就是为了处理最大值就是本身的情况。
一开始用的DFS,爆栈了,只有50分,换成BFS,才有70分,而且提示的错误很乱,后来发现edge数组开小了,改完居然就A掉了。。。
#include <cstdio> #include <algorithm> #include <queue> using namespace std; inline int get_num() { int num = 0; char c = getchar(); while (c < '0' || c > '9') c = getchar(); while (c >= '0' && c <= '9') num = num * 10 + c - '0', c = getchar(); return num; } const int maxn = 2e5 + 5; int head[maxn], eid; struct Edge { int v, next; } edge[2 * maxn]; inline void insert(int u, int v) { edge[++eid].v = v; edge[eid].next = head[u]; head[u] = eid; } int w[maxn], sum[maxn], maxw[maxn][2], fa[maxn], as, am; queue<int> q; inline void bfs() { q.push(1); fa[1] = 1; while (!q.empty()) { int u = q.front(); q.pop(); for (int p = head[u]; p; p = edge[p].next) { int v = edge[p].v; if (sum[v]) continue; fa[v] = u; q.push(v); sum[u] = (sum[u] + w[v]) % 10007; if (w[v] > maxw[u][0]) maxw[u][1] = maxw[u][0], maxw[u][0] = w[v]; else if (w[v] > maxw[u][1]) maxw[u][1] = w[v]; } } } inline void bfs2() { q.push(1); while (!q.empty()) { int u = q.front(); q.pop(); for (int p = head[u]; p; p = edge[p].next) { int v = edge[p].v; if (fa[u] == v) { as = (as + w[u] * (sum[v] - w[u]) % 10007) % 10007; if (w[u] == maxw[v][0]) am = max(am, w[u] * maxw[v][1]); else am = max(am, w[u] * maxw[v][0]); } else { as = (as + (2 * (w[u] * sum[v] % 10007) % 10007)) % 10007; am = max(am, w[u] * maxw[v][0]); q.push(v); } } } } int main() { int n, u, v; n = get_num(); for (int i = 1; i < n; ++i) { u = get_num(), v = get_num(); insert(u, v); insert(v, u); } for (int i = 1; i <= n; ++i) w[i] = get_num(); bfs(); bfs2(); printf("%d %d", am, as); return 0; }