题目传送门
题目大意
给定一个网络。网络分为$A$,$B$两个部分,每边各有$n$个点。对于$A_{i} \ (1\leqslant i < n)$会向$A_{i + 1}$连一条容量为$x_{i}$的有向边,对于$B_{i} \ (1\leqslant i < n)$会向$B_{i + 1}$连一条容量为$y_{i}$的有向边。$A$和$B$之间有$m$条边,起点为$A_{u_{i}}$,终点为$B_{v_{i}}$,容量为$w_{i}$的有向边。要求支持多次修改边的容量,询问$A_{1}$到$B_{n}$的最大流。
看起来不会退流的样子,所以应该可以用数据结构乱搞搞就能做出来。于是我想了很久但仍然不会。
因为最大流的流量等于最小割的容量,所以最大流不好做的时候考虑最小割。
直接考虑最小割的求解变成了最大流,这样没有用。考虑放宽一下约束条件,找一下怎样的割集是较优的。
一些显而易见的结论:
- 假如在$A$中,割掉$A_{x}$和$A_{x + 1}$之间的有向边,那么割掉$A_{y} \ (y > x)$与$A_{y + 1}$之间的有向边是没有意义的。
- 假如在$B$中,割掉$B_{x}$和$B_{x + 1}$之间的有向边,那么割掉$B_{y} \ (y < x)$与$B_{y + 1}$之间的有向边是没有意义的。
因此,在$A, B$中至多有一条边属于割集。
假设在$A$中被割掉的边是$(A_{x}, A_{x + 1})$,在$B$中被割掉的边是$B_{y}, B_{y + 1}$,那么任意$(A_{u}, B_{v}) \ (u \leqslant x \wedge v > y)$都是属于这个割集的。
因此,割的大小可以看做三部分:在$A$中的割集大小,在$B$中的割集大小,在$A, B$间的割集大小。
由于后两部分不会改变,考虑计算出它们。
考虑在$A$中从小到大枚举$A_{x}$,表示割掉$A_{x}$和$A_{x + 1}$之间的边,如果$x = n$表示不存在这条边。
那么下面要做的事情是在$B$中找到一个最优决策点$y$,使得后两部分的和最小。
对于每加入一条在$A,B$间的边,对答案造成的影响是连续的一段。
所以我们只需要写一个支持区间加,求$[1, n]$的最小值的线段树就好了。
到此,我们完美解决这道题了吗?
不,还剩下合并两部分的答案。这个可以用一个可删堆来维护。
时间复杂度$O((n + m + q)\log n)$。
Code
1 /** 2 * Codeforces 3 * Problem#903G 4 * Accepted 5 * Time: 451ms 6 * Memory: 31200k 7 */ 8 #include <bits/stdc++.h> 9 #ifdef WIN32 10 #define Auto "%I64d" 11 #else 12 #define Auto "%lld" 13 #endif 14 using namespace std; 15 16 #define ll long long 17 18 typedef class SegTreeNode { 19 public: 20 ll minv, lazy; 21 SegTreeNode *l, *r; 22 23 SegTreeNode():minv(0), lazy(0), l(NULL), r(NULL) { } 24 25 void pushUp() { 26 minv = min(l->minv, r->minv); 27 } 28 29 void pushDown() { 30 l->minv += lazy, r->minv += lazy; 31 l->lazy += lazy, r->lazy += lazy; 32 lazy = 0; 33 } 34 }SegTreeNode; 35 36 #define Limit 500000 37 38 SegTreeNode pool[Limit]; 39 SegTreeNode* top = pool; 40 41 SegTreeNode* newnode() { 42 return top++; 43 } 44 45 typedef class SegTree { 46 public: 47 SegTreeNode* rt; 48 49 SegTree() { } 50 SegTree(int n, int* ar) { 51 build(rt, 1, n, ar); 52 } 53 54 void build(SegTreeNode*& p, int l, int r, int *ar) { 55 p = newnode(); 56 if (l == r) { 57 p->minv = ar[l]; 58 return; 59 } 60 int mid = (l + r) >> 1; 61 build(p->l, l, mid, ar); 62 build(p->r, mid + 1, r, ar); 63 p->pushUp(); 64 } 65 66 void update(SegTreeNode*& p, int l, int r, int ql, int qr, int val) { 67 if (l == ql && r == qr) { 68 p->minv += val, p->lazy += val; 69 return; 70 } 71 if (p->lazy) p->pushDown(); 72 int mid = (l + r) >> 1; 73 if (qr <= mid) 74 update(p->l, l, mid, ql, qr, val); 75 else if (ql > mid) 76 update(p->r, mid + 1, r, ql, qr, val); 77 else { 78 update(p->l, l, mid, ql, mid, val); 79 update(p->r, mid + 1, r, mid + 1, qr, val); 80 } 81 p->pushUp(); 82 } 83 }SegTree; 84 85 #define pii pair<int, int> 86 87 typedef class Heap { 88 public: 89 priority_queue<ll> que; 90 priority_queue<ll> del; 91 92 Heap() { } 93 94 void insert(ll x) { 95 que.push(-x); 96 } 97 98 void remove(ll x) { 99 del.push(-x); 100 } 101 102 ll top() { 103 while (!que.empty() && !del.empty() && que.top() == del.top()) 104 que.pop(), del.pop(); 105 return -que.top(); 106 } 107 }Heap; 108 109 int n, m, q; 110 int *cs1, *cs2; 111 vector<pii> *g; 112 Heap hp; 113 SegTree st; 114 115 inline void init() { 116 scanf("%d%d%d", &n, &m, &q); 117 cs1 = new int[(n + 1)]; 118 cs2 = new int[(n + 1)]; 119 g = new vector<pii>[(n + 1)]; 120 cs1[n] = 0, cs2[1] = 0; 121 for (int i = 1; i < n; i++) 122 scanf("%d%d", cs1 + i, cs2 + i + 1); 123 for (int i = 1, u, v, w; i <= m; i++) { 124 scanf("%d%d%d", &u, &v, &w); 125 g[u].push_back(pii(v, w)); 126 } 127 } 128 129 ll *olds; 130 inline void solve() { 131 olds = new ll[(n + 1)]; 132 st = SegTree(n, cs2); 133 for (int i = 1; i <= n; i++) { 134 for (int j = 0; j < (signed) g[i].size(); j++) 135 st.update(st.rt, 1, n, 1, g[i][j].first, g[i][j].second); 136 hp.insert(olds[i] = cs1[i] + st.rt->minv); 137 // cerr << olds[i] << endl; 138 } 139 printf(Auto"\n", hp.top()); 140 int p, nw; 141 while (q--) { 142 scanf("%d%d", &p, &nw); 143 hp.remove(olds[p]); 144 olds[p] = olds[p] - cs1[p] + nw, cs1[p] = nw; 145 hp.insert(olds[p]); 146 printf(Auto"\n", hp.top()); 147 } 148 } 149 150 int main() { 151 init(); 152 solve(); 153 return 0; 154 }