题意:有 n座矿山,每座矿山有a[i] 的金子,两两相互连接的路径形成一棵树,有m个机器人,可以在顶点si 到ei这条路径上的矿山开矿(走过的路不能重复走),但是开采的总量不能超过wi,问最多能开采多少金子
思路:一开始没有看到形成一棵树,老想着有环怎么办。。。。
如果形成了一棵树,那么任意两点间只有一条路径可达(不能重复走),那么机器人只能在那些矿上上开采,机器人和那些山连上边就好了,只需预先处理一下LCA,查询的时候就能直接找到si到ei的路径,新建源点汇点,矿山和汇点连边,容量为矿山的总量,源点和机器人连线,容量为机器人最多能开采的总量,然后跑下裸的最大流。
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
typedef long long ll;
const ll INF = 1e18;
const ll maxn = 5 * 1e3 + 10;
using namespace std;
typedef struct ss {
ll to, cap, re;
ss(ll t, ll c, ll fl) {
to = t;
cap = c;
re = fl;
}
} st;
ll n, m, s, t;
ll a[maxn], lv[maxn];
vector<st> G[maxn];
vector<ll> g[maxn];
bool used[maxn];
ll it[maxn], vis[maxn];
ll anc[maxn][60];
ll pre[maxn], deep[maxn];
void init() {
for(ll i = 0; i < maxn; i++) {
G[i].clear();
g[i].clear();
}
memset(vis, 0, sizeof(vis));
memset(used, false, sizeof(used));
}
void build_tree(ll u) {
vis[u] = 1;
for(ll i = 0; i < g[u].size(); i++) {
ll v = g[u][i];
if(vis[v]) continue;
pre[v] = u;
build_tree(v);
}
}
void preprocess() {
for(ll i = 1; i <= n; i++) {
anc[i][0] = pre[i];
for(ll j = 1; (1 << j) < n; j++) anc[i][j] = -1;
}
for(ll j = 1; (1 << j) < n; j++) {
for(ll i = 1; i <= n; i++) {
if(anc[i][j - 1] == -1) continue;
ll a = anc[i][j - 1];
anc[i][j] = anc[a][j - 1];
}
}
}
ll query(ll p, ll q) {
ll lg;
if(deep[p] < deep[q]) swap(p, q);
for(lg = 1; (1 << lg) <= deep[p]; lg++); lg--;
for(ll i = lg; i >= 0; i--) {
if(deep[p] - (1 << i) >= deep[q]) {
p = anc[p][i];
}
}
if(p == q) return p;
ll i;
for(i = lg; i >= 0; i--) {
if(anc[p][i] != -1 && anc[p][i] != anc[q][i]) {
p = anc[p][i]; q = anc[q][i];
}
}
return anc[p][i];
}
void add(ll f, ll t, ll c) {
G[f].push_back(st(t, c, G[t].size()));
G[t].push_back(st(f, 0, G[f].size() - 1));
}
void bfs() {
memset(lv, -1, sizeof(lv));
queue<ll> q;
lv[s] = 0;
q.push(s);
while(!q.empty()) {
ll u = q.front(); q.pop();
for(ll i = 0; i < G[u].size(); i++) {
st &e = G[u][i];
if(e.cap > 0 && lv[e.to] < 0) {
lv[e.to] = lv[u] + 1;
q.push(e.to);
}
}
}
}
ll dfs(ll v, ll t, ll f) {
if(v == t) return f;
for(ll &i = it[v]; i < G[v].size(); i++) {
st &e = G[v][i];
if(e.cap > 0 && lv[v] < lv[e.to]) {
ll d = dfs(e.to, t, min(f, e.cap));
if(d > 0) {
e.cap -= d;
G[e.to][e.re].cap += d;
return d;
}
}
}
return 0;
}
ll maxflow() {
ll f = 0;
while(1) {
bfs();
if(lv[t] < 0) return f;
memset(it, 0, sizeof(it));
ll fl;
while((fl = dfs(s, t, INF)) > 0) f += fl;
}
}
int main() {
while(scanf("%lld %lld", &n, &m) != EOF) {
init();
s = 0; t = n + m + 1;
ll w, si, ei;
for(ll i = 1; i <= n; i++) {
scanf("%lld", &w);
add(i, t, w);
}
for(ll i = 0; i < n - 1; i++) {
ll uu, vv;
scanf("%lld %lld", &uu, &vv);
g[uu].push_back(vv);
g[vv].push_back(uu);
}
build_tree(1);
preprocess();
for(ll i = 1; i <= m; i++) {
scanf("%lld %lld %lld", &si, &ei, &w);
ll pr = query(si, ei);
add(s, n + i, w);
while(si != pr) { add(n + i, si, INF); si = pre[si]; }
while(ei != pr) { add(n + i, ei, INF); ei = pre[ei]; }
add(n + i, pr, INF);
}
ll ans = maxflow();
printf("%lld\n", ans);
}
return 0;
}