题意:一棵树,除了1号点根以外其他点都有怪,打每个怪扣
a i
a
i
点血,回复
b i
b
i
点血,必须要先击败他的父亲才能击败他,求最少需要多少血能打完所有的怪。
大致思路:经典的贪心 从这偷的
#include<bits/stdc++.h>
using namespace std ;
const int N = 1e5 + 10 ;
typedef long long ll;
struct node {
ll a, b, id;
node (ll a = 0 , ll b = 0 , ll id = 0 ) :a(a), b(b), id(id) {}
node operator + (const node &rhs) const {
ll tmp = max(a, a - b + rhs.a);
return node {tmp, rhs.b - rhs.a + b - a + tmp, id};
}
bool operator < (const node &rhs) const {
if (a < b && rhs.a < rhs.b) return a >= rhs.a;
if (a < b && rhs.a >= rhs.b) return 0 ;
if (a >= b && rhs.a < rhs.b) return 1 ;
if (a >= b && rhs.a >= rhs.b) return b < rhs.b;
}
}p[N];
priority_queue<node>pque;
int fa[N], vis[N];
vector <int > G[N];
int get_fa(int x) {
if (vis[fa[x]]) return fa[x] = get_fa(fa[x]);
return fa[x];
}
int t, n;
void dfs(int u, int pre) {
if (pre != -1 ) fa[u] = pre;
for (int v : G[u]) if (v != pre) dfs(v, u);
}
int main() {
scanf ("%d" , &t);
while (t--) {
scanf ("%d" , &n);
for (int i = 2 ; i <= n; i++) {
scanf ("%lld%lld" , &p[i].a, &p[i].b);
p[i].id = i;
pque.push(p[i]);
vis[i] = 0 ;
G[i].clear();
}
fa[1 ] = 1 ; G[1 ].clear(); vis[1 ] = 0 ; p[1 ].a = p[1 ].b = p[1 ].id = 0 ;
for (int i = 2 , u, v; i <= n; i++) {
scanf ("%d%d" , &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1 , -1 );
while (!pque.empty()) {
node now = pque.top();
pque.pop();
if (vis[now.id] || now.a != p[now.id].a || now.b != p[now.id].b) continue ;
vis[now.id] = 1 ;
int f = get_fa(now.id);
p[f] = p[f] + now;
if (f != 1 ) pque.push(p[f]);
}
printf ("%lld\n" , p[1 ].a);
}
}