CF#366 704D Captain America 上下界网络流

CF上的题,就不放链接了,打开太慢,直接上题面吧:

平面上有n个点, 第 i 个点的坐标为 ($X_i ,Y_i$), 你需要把每个点
染成红色或者蓝色, 染成红色的花费为 r , 染成蓝色的花费为 b .
有m个限制条件, 有两种类型, 第一种类型为$x = l_i$ 上的红点
与蓝点个数差的绝对值不超过 $d_i$, 第二种类型为$y= l_i$ 上的红
点与蓝点个数差的绝对值不超过 $d_i$.

 

题解:

  表示这题真的写到失去理想,因为是第一次写带上下限的网络最大流,一开始就把建图和统计代价理解错了好多次。。。

  首先我们可以观察到r, b是固定的,假设r比b小,那么我们就肯定要让涂红色尽可能多,这样才会更优。

  因此我们就不用考虑这个代价了,只需要找到一个合法的方案且使得涂红色的尽可能多即可。

  由于一个点要么涂红,要么涂蓝,因此我们并不需要求出涂蓝的个数,因为只要知道涂红的个数,涂蓝的个数自然就知道了。

  因此现在问题就被简化为了:

    二维平面上有n个点,有m个限制,要求被选中的点尽可能多。

  对于任何一个限制,假设这条线上有num个点,那么我们可以得出被选中点的上限和下限:$[\frac{num - d}{2}, \frac{num + d}{2}]$。

  而对于任何一个点是否被选,也可以看做有一个上限和下限$[0,1]$,即要么不选,要么选一个。
  那么我们将行和列分别用点表示,如果有点(x, y),那么从第x行向第y列连一条[0, 1]的边.

  对于x的限制,从s 到第x行连[下限,上限]的边。

  然后跑带上下限的最大流就可以知道最多选多少点了。

  如何不知道带上下限最大流怎么写请看:算法学习——带上下界网络流

  这题的建图因为还要离散化,所以写起来十分恶心。。。。

  代码比较冗长,建议只看思路。

  (注意在cf上提交的时候只能用I64d,不能用lld)

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define AC 500000
  5 #define ac 2000000
  6 #define inf 2139062143
  7 #define INF 2139062143
  8 #define LL long long
  9 
 10 int n, m, g, s, t, ss, ff, ww, tt, top1, top2, got, must;
 11 int cnt1, cnt2, x, head, tail, addflow;
 12 int Head[AC], Next[ac], belong[ac], date[ac], haveflow[ac], tot = 1;
 13 int lim1_x[AC], lim2_x[AC], lim1_y[AC], lim2_y[AC], q[AC];
 14 int num1[AC], num2[AC], q1[AC], q2[AC], c[AC], have[AC], good[AC], last[AC];
 15 bool z[AC], flag, vis1[AC], vis2[AC];
 16 LL d[AC], ans, red, blue;
 17 
 18 struct node{
 19     int x, y;
 20 }p[AC];
 21 
 22 inline int read()
 23 {
 24     int x = 0;char c = getchar();
 25     while(c > '9' || c < '0') c = getchar();
 26     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
 27     return x;
 28 }
 29 
 30 inline void add(int f, int w, int up, int down)
 31 {
 32     belong[tot] = f, date[++tot] = w, Next[tot] = Head[f], Head[f] = tot, haveflow[tot] = up - down, d[f] -= down;
 33     date[++tot] = f, Next[tot] = Head[w], Head[w] = tot, haveflow[tot] = 0, d[w] += down;
 34     if(w == tt) must += up - down;
 35 //    printf("%d ---> %d : %d\n", f, w, up - down); 
 36 }
 37 
 38 inline void upmin(int &a, int b)
 39 {
 40     if(b < a) a = b;
 41 }
 42 
 43 inline void upmax(int &a, int b)
 44 {
 45     if(b > a) a = b;
 46 }
 47 
 48 inline int half1(int x)
 49 {
 50     int l = 1, r = cnt1, mid; 
 51     while(l < r)
 52     {
 53         mid = (l + r) >> 1;
 54         if(q1[mid] > x) r = mid - 1;
 55         else if(q1[mid] < x) l = mid + 1;
 56         else return mid;
 57     }
 58     if(q1[l] != x) return 0;
 59     else return l;
 60 }
 61 
 62 inline int half2(int x)
 63 {
 64     int l = 1, r = cnt2, mid; 
 65     while(l < r)
 66     {
 67         mid = (l + r) >> 1;
 68         if(q2[mid] > x) r = mid - 1;
 69         else if(q2[mid] < x) l = mid + 1;
 70         else return mid;
 71     }
 72     if(q2[l] != x) return 0;
 73     else return l;
 74 }
 75 
 76 void link(int x)
 77 {
 78     if(d[x] > 0) add(ss, x, d[x], 0);
 79     else if(d[x] < 0) add(x, tt, -d[x], 0);
 80 }
 81 
 82 #define c c_
 83 #define d d_
 84 
 85 void get_lim()
 86 {
 87     int opt, a, b;
 88     for(R i = 1; i <= m; i ++)
 89     {
 90         opt = read(), a = read(), b = read();
 91         if(!a) continue;
 92         if(opt == 1)//x 的限制
 93         {
 94             a = half1(a);
 95             int c = (num1[a] + b) / 2, d = (num1[a] - b + 1) / 2;
 96             if(d > c) {puts("-1"); exit(0);}//,...这里需要判断
 97             upmin(lim1_x[a], c), upmax(lim1_y[a], d), vis1[a] = true;
 98         }
 99         else
100         {
101             a = half2(a);
102             int c = (num2[a] + b) / 2, d = (num2[a] - b + 1) / 2;
103             if(d > c) {puts("-1"); exit(0);}            
104             upmin(lim2_x[a], c), upmax(lim2_y[a], d), vis2[a] = true;
105         }
106     }
107 }
108 
109 void pre()
110 {
111     n = read(), m = read(), red = read(), blue = read();
112     s = n + m + 1, t = s + 1, ss = t + 1, tt = ss + 1;
113     memset(lim1_x, 127, sizeof(lim1_x));
114     memset(lim2_x, 127, sizeof(lim2_x));
115     for(R i = 1; i <= n; i ++) 
116         q1[++top1] = p[i].x = read(), q2[++top2] = p[i].y = read();
117     sort(q1 + 1, q1 + top1 + 1);
118     sort(q2 + 1, q2 + top2 + 1);
119     for(R i = 1; i <= top1; i ++)
120         if(q1[i] != q1[i + 1]) q1[++cnt1] = q1[i];
121     for(R i = 1; i <= top2; i ++)
122         if(q2[i] != q2[i + 1]) q2[++cnt2] = q2[i];
123     g = cnt1, ff = tot + 1;
124     for(R i = 1; i <= n; i ++)
125     {
126         p[i].x = half1(p[i].x), p[i].y = half2(p[i].y);
127         add(p[i].x, p[i].y + g, 1, 0);
128         ++num1[p[i].x], ++num2[p[i].y];
129     }
130     ww = tot;
131     get_lim();
132     for(R i = 1; i <= cnt1; i ++)
133         if(vis1[i]) add(s, i, lim1_x[i], lim1_y[i]);
134     for(R i = 1; i <= cnt2; i ++)
135         if(vis2[i]) add(i + g, t, lim2_x[i], lim2_y[i]);
136     for(R i = 1; i <= n; i ++)
137     {
138         if(!vis1[p[i].x])
139             vis1[p[i].x] = true, add(s, p[i].x, inf, 0);
140         if(!vis2[p[i].y])
141             vis2[p[i].y] = true, add(p[i].y + g, t, inf, 0);
142     }
143     add(t, s, inf, 0);
144     link(s), link(t);
145     for(R i = 1; i < s; i ++) link(i); 
146 }
147 #undef c
148 #undef d
149 
150 void bfs()
151 {
152     int x, now, k = flag ? t : tt;
153     if(flag) memset(have, 0, sizeof(have));
154     if(flag) memset(c, 0, sizeof(c));
155     head = tail = 0;
156     q[++tail] = k, c[k] = 1, have[1] = 1;
157     while(head < tail)
158     {
159         x = q[++head];
160         for(R i = Head[x]; i; i = Next[i])
161         {
162             now = date[i];
163             if(flag && (now == ss || now == tt)) continue;
164             if(!c[now]/* && haveflow[i ^ 1]*/)
165             {
166                 c[now] = c[x] + 1;
167                 q[++tail] = now;
168                 ++ have[c[now]];
169             }
170         }
171     }
172     memcpy(good, Head, sizeof(Head));
173 }    
174 
175 void aru()
176 {
177     int k = flag ? s : ss;
178     while(x != k)
179     {
180         //if(flag) printf("%d ---> %d\n", x, date[last[x] ^ 1]);
181         haveflow[last[x]] -= addflow;
182         haveflow[last[x] ^ 1] += addflow;
183         x = date[last[x] ^ 1];
184     }
185     //printf("\n\n");
186     if(flag) ans += addflow;
187     else got += addflow;
188 }
189 
190 void isap()
191 {
192     int now; bool done;int k = flag ? t : tt, kk = flag ? s : ss;
193     addflow = inf, x = kk;
194     while(c[kk] != k + 10)
195     {
196         if(x == k) aru(), addflow = inf;
197         done = false;
198         for(R i = good[x]; i; i = Next[i])
199         {
200             now = date[i];
201             if(flag && (now == ss || now == tt)) continue;
202             if(c[now] == c[x] - 1 && haveflow[i])
203             {
204                 upmin(addflow, haveflow[i]);
205                 good[x] = i, last[now] = i;
206                 x = now, done = true;
207                 break;
208             }
209         }
210         if(!done)
211         {
212             int go = k + 9;
213             for(R i = Head[x]; i; i = Next[i])
214             {
215                 now = date[i];
216                 if(flag && (now == ss || now == tt)) continue;
217                 if(haveflow[i] && c[now]) upmin(go, c[now]);
218             }
219             if(!(-- have[c[x]])) break;
220             ++have[c[x] = go + 1];
221             good[x] = Head[x];
222             if(x != kk) x = date[last[x] ^ 1];
223         }
224     }
225 }
226 
227 void write(bool k)
228 {
229     if(k)
230     {
231         if(red < blue) putchar('r');
232         else putchar('b');
233     }
234     else
235     {
236         if(red > blue) putchar('r');
237         else putchar('b');
238     }
239 }
240 
241 void find()
242 {
243     for(R i = ff; i <= ww; i += 2) write(haveflow[i ^ 1]);
244     printf("\n");
245 }
246 
247 void work()
248 {
249     LL k = min(red, blue), kk = max(red, blue);
250     flag = true;
251     if(got != must) {puts("-1"); return ;}
252     bfs();
253     isap();
254     ans = k * ans + kk * (n - ans);
255     printf("%lld\n", ans);
256     find();
257 }
258 
259 int main()
260 {
261     freopen("in.in", "r", stdin);
262     pre();
263     bfs();
264     isap();
265     work();
266     fclose(stdin);
267     return 0;
268 }
View Code

 

posted @ 2018-09-25 01:14  ww3113306  阅读(880)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。