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)

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 500000
#define ac 2000000
#define inf 2139062143
#define INF 2139062143
#define LL long long int n, m, g, s, t, ss, ff, ww, tt, top1, top2, got, must;
int cnt1, cnt2, x, head, tail, addflow;
int Head[AC], Next[ac], belong[ac], date[ac], haveflow[ac], tot = ;
int lim1_x[AC], lim2_x[AC], lim1_y[AC], lim2_y[AC], q[AC];
int num1[AC], num2[AC], q1[AC], q2[AC], c[AC], have[AC], good[AC], last[AC];
bool z[AC], flag, vis1[AC], vis2[AC];
LL d[AC], ans, red, blue; struct node{
int x, y;
}p[AC]; inline int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} inline void add(int f, int w, int up, int down)
{
belong[tot] = f, date[++tot] = w, Next[tot] = Head[f], Head[f] = tot, haveflow[tot] = up - down, d[f] -= down;
date[++tot] = f, Next[tot] = Head[w], Head[w] = tot, haveflow[tot] = , d[w] += down;
if(w == tt) must += up - down;
// printf("%d ---> %d : %d\n", f, w, up - down);
} inline void upmin(int &a, int b)
{
if(b < a) a = b;
} inline void upmax(int &a, int b)
{
if(b > a) a = b;
} inline int half1(int x)
{
int l = , r = cnt1, mid;
while(l < r)
{
mid = (l + r) >> ;
if(q1[mid] > x) r = mid - ;
else if(q1[mid] < x) l = mid + ;
else return mid;
}
if(q1[l] != x) return ;
else return l;
} inline int half2(int x)
{
int l = , r = cnt2, mid;
while(l < r)
{
mid = (l + r) >> ;
if(q2[mid] > x) r = mid - ;
else if(q2[mid] < x) l = mid + ;
else return mid;
}
if(q2[l] != x) return ;
else return l;
} void link(int x)
{
if(d[x] > ) add(ss, x, d[x], );
else if(d[x] < ) add(x, tt, -d[x], );
} #define c c_
#define d d_ void get_lim()
{
int opt, a, b;
for(R i = ; i <= m; i ++)
{
opt = read(), a = read(), b = read();
if(!a) continue;
if(opt == )//x 的限制
{
a = half1(a);
int c = (num1[a] + b) / , d = (num1[a] - b + ) / ;
if(d > c) {puts("-1"); exit();}//,...这里需要判断
upmin(lim1_x[a], c), upmax(lim1_y[a], d), vis1[a] = true;
}
else
{
a = half2(a);
int c = (num2[a] + b) / , d = (num2[a] - b + ) / ;
if(d > c) {puts("-1"); exit();}
upmin(lim2_x[a], c), upmax(lim2_y[a], d), vis2[a] = true;
}
}
} void pre()
{
n = read(), m = read(), red = read(), blue = read();
s = n + m + , t = s + , ss = t + , tt = ss + ;
memset(lim1_x, , sizeof(lim1_x));
memset(lim2_x, , sizeof(lim2_x));
for(R i = ; i <= n; i ++)
q1[++top1] = p[i].x = read(), q2[++top2] = p[i].y = read();
sort(q1 + , q1 + top1 + );
sort(q2 + , q2 + top2 + );
for(R i = ; i <= top1; i ++)
if(q1[i] != q1[i + ]) q1[++cnt1] = q1[i];
for(R i = ; i <= top2; i ++)
if(q2[i] != q2[i + ]) q2[++cnt2] = q2[i];
g = cnt1, ff = tot + ;
for(R i = ; i <= n; i ++)
{
p[i].x = half1(p[i].x), p[i].y = half2(p[i].y);
add(p[i].x, p[i].y + g, , );
++num1[p[i].x], ++num2[p[i].y];
}
ww = tot;
get_lim();
for(R i = ; i <= cnt1; i ++)
if(vis1[i]) add(s, i, lim1_x[i], lim1_y[i]);
for(R i = ; i <= cnt2; i ++)
if(vis2[i]) add(i + g, t, lim2_x[i], lim2_y[i]);
for(R i = ; i <= n; i ++)
{
if(!vis1[p[i].x])
vis1[p[i].x] = true, add(s, p[i].x, inf, );
if(!vis2[p[i].y])
vis2[p[i].y] = true, add(p[i].y + g, t, inf, );
}
add(t, s, inf, );
link(s), link(t);
for(R i = ; i < s; i ++) link(i);
}
#undef c
#undef d void bfs()
{
int x, now, k = flag ? t : tt;
if(flag) memset(have, , sizeof(have));
if(flag) memset(c, , sizeof(c));
head = tail = ;
q[++tail] = k, c[k] = , have[] = ;
while(head < tail)
{
x = q[++head];
for(R i = Head[x]; i; i = Next[i])
{
now = date[i];
if(flag && (now == ss || now == tt)) continue;
if(!c[now]/* && haveflow[i ^ 1]*/)
{
c[now] = c[x] + ;
q[++tail] = now;
++ have[c[now]];
}
}
}
memcpy(good, Head, sizeof(Head));
} void aru()
{
int k = flag ? s : ss;
while(x != k)
{
//if(flag) printf("%d ---> %d\n", x, date[last[x] ^ 1]);
haveflow[last[x]] -= addflow;
haveflow[last[x] ^ ] += addflow;
x = date[last[x] ^ ];
}
//printf("\n\n");
if(flag) ans += addflow;
else got += addflow;
} void isap()
{
int now; bool done;int k = flag ? t : tt, kk = flag ? s : ss;
addflow = inf, x = kk;
while(c[kk] != k + )
{
if(x == k) aru(), addflow = inf;
done = false;
for(R i = good[x]; i; i = Next[i])
{
now = date[i];
if(flag && (now == ss || now == tt)) continue;
if(c[now] == c[x] - && haveflow[i])
{
upmin(addflow, haveflow[i]);
good[x] = i, last[now] = i;
x = now, done = true;
break;
}
}
if(!done)
{
int go = k + ;
for(R i = Head[x]; i; i = Next[i])
{
now = date[i];
if(flag && (now == ss || now == tt)) continue;
if(haveflow[i] && c[now]) upmin(go, c[now]);
}
if(!(-- have[c[x]])) break;
++have[c[x] = go + ];
good[x] = Head[x];
if(x != kk) x = date[last[x] ^ ];
}
}
} void write(bool k)
{
if(k)
{
if(red < blue) putchar('r');
else putchar('b');
}
else
{
if(red > blue) putchar('r');
else putchar('b');
}
} void find()
{
for(R i = ff; i <= ww; i += ) write(haveflow[i ^ ]);
printf("\n");
} void work()
{
LL k = min(red, blue), kk = max(red, blue);
flag = true;
if(got != must) {puts("-1"); return ;}
bfs();
isap();
ans = k * ans + kk * (n - ans);
printf("%lld\n", ans);
find();
} int main()
{
freopen("in.in", "r", stdin);
pre();
bfs();
isap();
work();
fclose(stdin);
return ;
}

最新文章

  1. 使用ANTS Performance Profiler&amp;ANTS Memory Profiler工具分析IIS进程内存和CPU占用过高问题
  2. 微信小程序组件-----城市切换
  3. 我的ORM之二--添加
  4. 51job前程无忧网站打不开,51job网站进不了,51job打不开
  5. css3浏览器前缀 -mos/-webkit/-o/-ms
  6. 手写js面向对象选项卡插件
  7. JBoss for luna
  8. 宣布发布全新的 Windows Azure 缓存预览版
  9. Servlet的学习之Cookie
  10. sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  11. 彻底卸载 postgreSQL .etc
  12. 关于mysql中的DDL,DML,DQL和DCL
  13. https进行配置以及http跳转到https配置
  14. Scala:First Steps in Scala
  15. ubuntu之redis集群配置
  16. 在CentOS 7上使用Tripwire监控和检测修改的文件
  17. DevExpress04、LayoutControl、GalleryControl
  18. 转自《https安全链接的配置教程:startSSl免费证书申请与nginx的https支持配置》
  19. 交互神器-最好用的Mac原型设计工具
  20. Go语言优势与劣势

热门文章

  1. JS高级. 06 缓存、分析解决递归斐波那契数列、jQuery缓存、沙箱、函数的四种调用方式、call和apply修改函数调用方法
  2. php面向对象基础知识整理之类中的属性和方法的使用
  3. MySQL5.7版本安装
  4. [转]App离线本地存储方案
  5. ELK的简述安装
  6. Python3 time模块&amp;datetime模块&amp;random模块
  7. go学习笔记-变量作用域
  8. express操作数据库
  9. CC3200模块的内存地址划分和bootloader(一)
  10. 杀死 tomcat 进程的脚本