Codeforces 903G Yet Another Maxflow Problem - 线段树

题目传送门

  传送门I

  传送门II

  传送门III

题目大意

  给定一个网络。网络分为$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 }
posted @ 2018-04-05 22:20  阿波罗2003  阅读(285)  评论(0编辑  收藏  举报