luogu P6122 [NEERC2016]Mole Tunnels
阿新 • • 發佈:2021-12-17
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; }