1. 程式人生 > 其它 >luogu P6122 [NEERC2016]Mole Tunnels

luogu P6122 [NEERC2016]Mole Tunnels

https://www.luogu.com.cn/problem/P6122

NB模擬費用流題
費用流的建圖不難,我們考慮如何模擬這個過程

可以暴力模擬這個過程因為樹的高度只有\(log n\)所以可以暴力去找增廣路,然後暴力增廣

維護一下每個點兒子中最近的關鍵點即可
然後記錄一下每條邊的流量和方向

code:

#include<bits/stdc++.h>
#define N 400050
using namespace std;
int flow[N], dis[N], pos[N], a[N], n, m;
int UP(int u) {
    return flow[u] < 0 ? - 1 : 1;
}
int DOWN(int u) {
    return flow[u] > 0 ? - 1 : 1;
}
#define ls (rt << 1)
#define rs (rt << 1 | 1)
const int inf = 1e9;
void update(int rt) {
    pos[rt] = 0, dis[rt] = inf;
    if(a[rt]) pos[rt] = rt, dis[rt] = 0;
    if(dis[rt] > dis[ls] + DOWN(ls)) dis[rt]  = dis[ls] + DOWN(ls), pos[rt] = pos[ls];
    if(dis[rt] > dis[rs] + DOWN(rs)) dis[rt]  = dis[rs] + DOWN(rs), pos[rt] = pos[rs];
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    for(int i = n + 1; i <= n + n + 1; i ++) dis[i] = inf;
    for(int i = n; i >= 1; i --) update(i);

    int ans = 0;
    while(m --) {
        int x = 0, y = 0, z = 0, ret = 1e9, now = 0;
        scanf("%d", &x);
        for(int u = x; u; u >>= 1) {
            if(ret > now + dis[u]) ret = now + dis[u], z = u;
            now += UP(u);
        }
        
        y = pos[z];
        ans += ret;
       // printf("%d   %d %d %d   %d\n", ans, x, y, z, dis[5]);
        printf("%d ", ans);
        a[y] --;
         for(int u = x; u != z; u >>= 1) flow[u] ++;
         for(int u = y; u != z; u >>= 1) flow[u] --;

         for(int u = y; u != z; u >>= 1) update(u);
         for(int u = x; u ; u >>= 1) update(u);
        
    }
    return 0;
}