1. 程式人生 > >Codeforces Gym 101190M Mole Tunnels - 費用流

Codeforces Gym 101190M Mole Tunnels - 費用流

題目傳送門

  傳送門

題目大意

  $m$只鼴鼠有$n$個巢穴,$n - 1$條長度為$1$的通道將它們連通且第$i(i > 1)$個巢穴與第$\left\lfloor \frac{i}{2}\right\rfloor$個巢穴連通。第$i$個巢穴在最終時允許$c_i$只醒來的鼴鼠最終停留在這。已知第$i$只鼴鼠在第$p_i$個巢穴睡覺。要求求出對於每個滿足$1 \leqslant k \leqslant n$的$k$,如果前$k$只鼴鼠醒來,最小的移動距離的總和。

  考慮費用流的建圖和暴力做法,把原圖的邊容量設為無限大,費用設為1(每條無向邊要拆成兩條),每個點再向匯點連一條邊,容量為$c_i$,費用為0。

  對於每次源點向$p_i$增廣1單位的流量。

  顯然這樣會超時,考慮優化費用流。

  顯然有:

  • 每次增廣的路徑一定是一條簡單路徑
  • 對於原圖的一條無向邊,它兩個方向的邊不會同時有流量(走另外一條弧的反向弧顯然可以減少費用)

  那麼每次列舉路徑的LCA,對於每個點記錄一下$f_i$表示從$i$走到子樹內的任意一個點的最短距離。

  顯然每次更新邊權後很容易能夠維護$f$。時間複雜度$O(n\log n)$。

Code

  1 /**
  2  * Codeforces
  3  * Gym#101190M
  4  * Accepted
  5  * Time: 108ms
6 * Memory: 2200k 7 */ 8 #include <iostream> 9 #include <cstdlib> 10 #include <cstdio> 11 #ifndef WIN32 12 #define Auto "%lld" 13 #else 14 #define Auto "%I64d" 15 #endif 16 using namespace std; 17 typedef bool boolean; 18 19 #define ll long long 20 21
const signed ll llf = (signed ll) (~0ull >> 3); 22 const signed int inf = (signed) (~0u >> 2); 23 const int N = 131072; 24 25 #define pii pair<int, int> 26 27 pii operator + (pii a, int b) { 28 return pii(a.first + b, a.second); 29 } 30 31 int n, m; 32 int w[N], c[N]; 33 pii fd[N]; 34 35 inline void init() { 36 scanf("%d%d", &n, &m); 37 for (int i = 1; i <= n; i++) { 38 scanf("%d", c + i); 39 } 40 } 41 42 int value(int p, int dir) { // up : +1, down : -1 43 int prod = w[p] * dir; 44 return (prod >= 0) ? (1) : (-1); 45 } 46 47 void __update(int p) { 48 fd[p] = pii(inf * (!c[p]), p); 49 if ((p << 1) <= n && fd[p << 1].first != inf) 50 fd[p] = min(fd[p], fd[p << 1] + value(p << 1, -1)); 51 if ((p << 1) < n && fd[p << 1 | 1].first != inf) 52 fd[p] = min(fd[p], fd[p << 1 | 1] + value(p << 1 | 1, -1)); 53 } 54 55 int update(int s) { 56 int val = fd[s].first, g = s, v = fd[s].second, len = 0; 57 for (int p = s, d = (p & 1), q, cmp; len += value(p, 1), p >>= 1; d = p & 1) { 58 q = p << 1 | (d ^ 1); 59 if (q <= n && (cmp = fd[q].first + value(q, -1) + len) < val) 60 val = cmp, g = p, v = fd[q].second; 61 if (c[p] && len < val) 62 val = len, g = v = p; 63 } 64 c[v]--; 65 for (int p = s; p != g; p >>= 1) { 66 w[p]++; 67 __update(p); 68 } 69 for (int p = v; p != g; p >>= 1) { 70 w[p]--; 71 __update(p); 72 } 73 for (int p = g; p; p >>= 1) 74 __update(p); 75 // cerr << s << " " << v << '\n'; 76 return val; 77 } 78 79 inline void solve() { 80 for (int i = 1; i <= n; i++) 81 fd[i] = pii(inf * (!c[i]), i); 82 for (int i = n; i > 1; i--) 83 fd[i >> 1] = min(fd[i >> 1], fd[i] + 1); 84 85 int x; 86 ll res = 0; 87 while (m--) { 88 scanf("%d", &x); 89 res += update(x); 90 printf(Auto" ", res); 91 } 92 } 93 94 int main() { 95 freopen("mole.in", "r", stdin); 96 freopen("mole.out", "w", stdout); 97 init(); 98 solve(); 99 return 0; 100 }