哈尔滨理工大学软件学院ACM程序设计全国邀请赛 A Golds(LCA + 最大流)

来源:互联网 发布:linux删除文件中的内容 编辑:程序博客网 时间:2024/05/02 02:27

题意:有 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;}


0 0