AT_arc098_d Donation 题解
teylnol_evteyl · · 题解
一道在 kruskal 重构树上 DP 的题。
首先,捐钱比较难想,可以反过来思考倒着走领钱的思路。
显然,在第一次经过一个节点的时候领钱是最优的,对于节点
对于边
考虑在这棵树上 dp。设
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 5;
int n, k, m, a[N], b[N];
struct edge{
int u, v, w;
bool operator <(const edge &p) const
{
return w < p.w;
}
}e[N];
int pe[N];
int fa[N], ls[N], rs[N];
LL f[N], s[N];
int gfa(int i)
{
return i == pe[i] ? i : (pe[i] = gfa(pe[i]));
}
void kruskal()
{
for(int i = 1; i < n * 2; i ++ ) pe[i] = i;
k = n;
sort(e + 1, e + m + 1);
for(int i = 1; i <= m; i ++ )
{
int u = gfa(e[i].u), v = gfa(e[i].v);
if(u != v)
{
fa[u] = fa[v] = pe[u] = pe[v] = ++ k;
ls[k] = u, rs[k] = v;
a[k] = e[i].w;
}
}
}
void dp()
{
for(int u = 1; u <= n; u ++ )
{
f[u] = a[u] + b[u];
s[u] = b[u];
}
for(int u = n + 1; u <= k; u ++ )
{
s[u] = s[ls[u]] + s[rs[u]];
f[u] = min(max(f[ls[u]], (LL)a[u]) + s[u] - s[ls[u]], max(f[rs[u]], (LL)a[u]) + s[u] - s[rs[u]]);
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++ )
{
scanf("%d%d", &a[i], &b[i]);
a[i] = max(a[i] - b[i], 0);
}
for(int i = 1; i <= m; i ++ )
{
scanf("%d%d", &e[i].u, &e[i].v);
e[i].w = max(a[e[i].u], a[e[i].v]);
}
kruskal();
dp();
printf("%lld\n", f[k]);
return 0;
}