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)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }