送你一朵圣诞树
题目背景:
分析:并查集 + 堆 + 贪心
对于全局最小的那个点,选择了它的父亲之后,就一定会选择它,所以我们直接合并它和它的父亲,那么对于一个点集i,记录ti为点集中的点的个数,Si为点集中的点的权值和,那么,对于两个点集,如果点集i优于点集j,那么ti * sj > tj * si,那么si /ti < sj / tj,那么直接并查集 + 堆,每次合并当前块和父亲的块就可以了。
Source:
/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
inline char read() {
static const int IN_LEN = 1024 * 1024;
static char buf[IN_LEN], *s, *t;
if (s == t) {
t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
if (s == t) return -1;
}
return *s++;
}
///*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return ;
if (c == '-') iosig = true;
}
for (x = 0; isdigit(c); c = read())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {
if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
*oh++ = c;
}
template<class T>
inline void W(T x) {
static int buf[30], cnt;
if (x == 0) write_char('0');
else {
if (x < 0) write_char('-'), x = -x;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
while (cnt) write_char(buf[cnt--]);
}
}
inline void flush() {
fwrite(obuf, 1, oh - obuf, stdout);
}
/*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
if (c == '-') iosig = true;
for (x = 0; isdigit(c); c = getchar())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int MAXN = 30000 + 10;
struct node {
int to, s, t;
node(int to = 0, int s = 0, int t = 0) : to(to), s(s), t(t) {}
inline bool operator < (const node &a) const {
return (double)s / t > (double)a.s / a.t;
}
} ;
std::priority_queue<node> q;
std::vector<int> edge[MAXN];
int n, x, y, val;
int w[MAXN], deg[MAXN], father[MAXN], sum[MAXN], size[MAXN], fa[MAXN];
bool able[MAXN];
inline void add_edge(int x, int y) {
edge[x].push_back(y), edge[y].push_back(x);
}
inline void read_in() {
R(n);
for (int i = 1; i < n; ++i) R(x), R(y), add_edge(x, y);
for (int i = 1; i <= n; ++i) R(w[i]), R(able[i]);
}
inline void dfs(int cur, int fa) {
deg[cur] = 0;
for (int p = 0; p < edge[cur].size(); ++p) {
int v = edge[cur][p];
if (v != fa) father[v] = cur, dfs(v, cur), deg[cur]++;
}
}
inline int get_father(int x) {
return (fa[x] == x) ? (x) : (fa[x] = get_father(fa[x]));
}
inline void solve() {
long long ans = 0;
for (int i = 1; i <= n; ++i) {
if (able[i]) {
dfs(i, 0);
long long ret = 0;
while (!q.empty()) q.pop();
for (int j = 1; j <= n; ++j) {
if (j != i) q.push(node(j, w[j], 1));
sum[j] = w[j], size[j] = 1, ret += w[j], fa[j] = j;
}
while (!q.empty()) {
node temp = q.top();
int cur = q.top().to;
q.pop();
if (get_father(cur) != cur || size[cur] != temp.t) continue ;
int fa = get_father(father[cur]);
// std::cout << "cur == " << cur << " " << fa << '\n';
// std::cout << size[cur] << " " << sum[cur] << " " << size[fa] << " " << sum[fa] << '\n';
ret += (long long)size[fa] * sum[cur], ::fa[cur] = fa;
size[fa] += size[cur], sum[fa] += sum[cur];
if (fa != i) q.push(node(fa, sum[fa], size[fa]));
}
ans = std::max(ans, ret);
}
}
std::cout << ans;
}
int main() {
freopen("xmastree2.in", "r", stdin);
freopen("xmastree2.out", "w", stdout);
read_in();
solve();
return 0;
}