题意:平面上有n个点,每个点必须涂成红色和蓝色中的一种,花费各为r和b(对所有的点花费都一样).m条限制,每条限制形如”y=b这条直线上两种颜色的点的数目之差的绝对值不能超过c”或” x=b这条直线上两种颜色的点的数目之差的绝对值不能超过c”,点数和限制数10^5,坐标范围10^9.

首先看到坐标范围很大先离散化,然后变成100000*100000的网格图每行每列的限制.那么转化成二分图,原先的每个点转换成边.因为每一行每一列的总点数是已知的,”两种颜色的点的数目之差”就可以转化成红色点和蓝色点的数目范围.接下来不妨把所有点都涂成红色,然后如果蓝色的点比红色的点花费小我们就尽量多涂蓝点,否则尽量少涂蓝点.为了统一问题的形式,在蓝色的点花费小于红色的时候我们就先全涂上蓝色,然后尽量少涂红点.不妨认为现在红色点花费较少,先涂上红点再尽量少涂蓝点.

那么就成了有上下界的网络流问题.对第i行我们建一个点Li,对第j列我们建一个点Ri,从源点向每个Li连一条流量上下界为这一行的蓝色点数目范围的边(在求解蓝点数目范围的时候要考虑到蓝点的数目还应当大于等于0小于等于这一行/列的点数),对每个Ri向汇点连一条流量上下界为这一列的蓝色点数目范围的边,对于坐标为第i行第j列的点,我们从Li向Rj连一条下界为0上界为1的边.跑有上下界的最小流即可.

注意一开始求的蓝点的数目范围可能是空集,这时候直接输出-1,不要再dinic跑可行流了.不知道别人的代码怎么样,反正我的代码很矬,即使有下界>上界的边也能跑出个可行流…

代码稍微长点.

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

typedef long long ll;

const int maxn=,maxm=;

struct edge{

  int to,next,w,num;

}lst[maxm];int len=,first[maxn],_first[maxn];

void addedge(int a,int b,int w,int num=){

  lst[len].num=num;

  lst[len].to=b;lst[len].next=first[a];lst[len].w=w;first[a]=len++;

  lst[len].num=num;

  lst[len].to=a;lst[len].next=first[b];lst[len].w=;first[b]=len++;

}

int q[maxn],vis[maxn],dis[maxn],s,t,head,tail,T;

bool bfs(){

  head=tail=;vis[s]=++T;dis[s]=;q[tail++]=s;

  while(head!=tail){

    int x=q[head++];

    for(int pt=first[x];pt!=-;pt=lst[pt].next){

      if(lst[pt].w&&vis[lst[pt].to]!=T){

        vis[lst[pt].to]=T;dis[lst[pt].to]=dis[x]+;q[tail++]=lst[pt].to;

      }

    }

  }

  if(vis[t]==T)memcpy(_first,first,sizeof(first));

  return vis[t]==T;

}

int dfs(int x,int lim){

  if(x==t)return lim;

  int flow=,a;

  for(int pt=_first[x];pt!=-;pt=lst[pt].next){

    _first[x]=pt;

    if(lst[pt].w&&dis[lst[pt].to]==dis[x]+&&(a=dfs(lst[pt].to,min(lst[pt].w,lim-flow)))){

      lst[pt].w-=a;lst[pt^].w+=a;flow+=a;

      if(flow==lim)return flow;

    }

  }

  return flow;

}

int dinic(){

  int ans=,x;

  while(bfs())

    while(x=dfs(s,0x7f7f7f7f))ans+=x;

  return ans;

}

void del(int x){

  for(int pt=first[x];pt!=-;pt=lst[pt].next)lst[pt].w=lst[pt^].w=;

}

int totflow[maxn];

int bound_flow(){//s-t minimum flow with lowerbound and upperbound

  int ss=t+,tt=t+;

  int sum=;

  for(int i=s;i<=t;++i){

    if(totflow[i]<){

      addedge(i,tt,-totflow[i]);

    }else{

      sum+=totflow[i];

      addedge(ss,i,totflow[i]);

    }

  }

  addedge(t,s,0x7f7f7f7f);

  int tmps=s,tmpt=t;

  s=ss;t=tt;

  if(dinic()!=sum){

    printf("-1\n");return -;

  }else{//return 0;

    int ans0=lst[len-].w;

    lst[len-].w=lst[len-].w=;

    del(ss);del(tt);

    s=tmpt;t=tmps;//printf("!");

    return ans0-dinic();

  }

}

void Add(int a,int b,int lo,int hi,int num=){//printf("%d %d %d %d\n",a,b,lo,hi);

  totflow[a]-=lo;totflow[b]+=lo;

  addedge(a,b,hi-lo,num);

}

int n,m,r,b;

int x[maxn],y[maxn],typ[maxn],pos[maxn],delta[maxn];

int lbx[maxn],ubx[maxn],lby[maxn],uby[maxn];

int val[maxn],seq[maxn];

bool cmp(const int &a,const int &b){

  return val[a]<val[b];

}

int discrete(int x[],int _typ){

  int tot=,old=-,cnt=;

  for(int i=;i<=n;++i){

    val[++tot]=x[i];

  }

  for(int i=;i<=m;++i){

    if(typ[i]==_typ)val[++tot]=pos[i];

  }

  for(int i=;i<=tot;++i)seq[i]=i;

  sort(seq+,seq+tot+,cmp);

  for(int i=;i<=tot;++i){

    if(val[seq[i]]!=old){

      old=val[seq[i]];++cnt;

    }

    val[seq[i]]=cnt;

  }

  tot=;

  for(int i=;i<=n;++i){

    x[i]=val[++tot];

  }

  for(int i=;i<=m;++i){

    if(typ[i]==_typ)pos[i]=val[++tot];

  }

  return cnt;

}

int cntx[maxn],cnty[maxn];

int res[maxn];

int main(){

  memset(first,-,sizeof(first));

  scanf("%d%d",&n,&m);

  scanf("%d%d",&r,&b);

  bool reversed = false;

  if(r>b)swap(r,b),reversed=true;

  for(int i=;i<=n;++i){

    scanf("%d%d",&x[i],&y[i]);

  }

  for(int i=;i<=m;++i){

    scanf("%d%d%d",typ+i,pos+i,delta+i);

  }

  int totx=discrete(x,),toty=discrete(y,);

  //for(int i=1;i<=n;++i)printf("%d %d\n",x[i],y[i]);

  //for(int i=1;i<=m;++i)printf("%d %d %d\n",typ[i],pos[i],delta[i]);

  for(int i=;i<=n;++i)cntx[x[i]]++,cnty[y[i]]++;

  ll ans=r*1LL*n;

  for(int i=;i<=totx;++i){

    lbx[i]=;ubx[i]=cntx[i];

  }

  for(int i=;i<=toty;++i){

    lby[i]=;uby[i]=cnty[i];

  }

  for(int i=;i<=m;++i){

    if(typ[i]==){

      lbx[pos[i]]=max(lbx[pos[i]],(cntx[pos[i]]-delta[i]+)/);ubx[pos[i]]=min(ubx[pos[i]],(cntx[pos[i]]+delta[i])/);

    }else{

      lby[pos[i]]=max(lby[pos[i]],(cnty[pos[i]]-delta[i]+)/);uby[pos[i]]=min(uby[pos[i]],(cnty[pos[i]]+delta[i])/);

    }

  }

  s=;t=totx+toty+;

  bool no_solution=false;

  for(int i=;i<=totx;++i){

    Add(s,i,lbx[i],ubx[i]);

    if(lbx[i]>ubx[i])no_solution=true;//神坑

  }//printf("!");

  for(int i=;i<=toty;++i){

    Add(totx+i,t,lby[i],uby[i]);

    if(lby[i]>uby[i])no_solution=true;//神坑

  }//printf("!");

  for(int i=;i<=n;++i){//printf("!");

    Add(x[i],totx+y[i],,,i);

  }//printf("!");

  if(no_solution){

    printf("-1\n");return ;

  }

  int flow=bound_flow();

  if(flow!=-){

    printf("%lld\n",ans+flow*1LL*(b-r));

    for(int i=;i<=totx;++i){

      for(int pt=first[i];pt!=-;pt=lst[pt].next){

        if(lst[pt].num!=&&lst[pt].w==){

          res[lst[pt].num]=;

        }

      }

    }//printf("?");

    if(reversed){

      for(int i=;i<=n;++i)printf("%c",res[i]?'r':'b');

    }else{

      for(int i=;i<=n;++i)printf("%c",res[i]?'b':'r');

    }printf("\n");

  }

  return ;

}

Codeforces 704D Captain America的更多相关文章

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

    CF上的题,就不放链接了,打开太慢,直接上题面吧: 平面上有n个点, 第 i 个点的坐标为 ($X_i ,Y_i$), 你需要把每个点染成红色或者蓝色, 染成红色的花费为 r , 染成蓝色的花费为 b ...

  2. CF 704 D. Captain America

    CF 704 D. Captain America 题目链接 题目大意:给出\(n\)个点的坐标,你要将每个点染成红色或者蓝色.染一个红色要付出\(r\)的代价,染一个蓝色要付出\(b\)的代价.有\ ...

  3. 【CF704D】Captain America(上下界网络流)

    [CF704D]Captain America(上下界网络流) 题面 CF 洛谷 题解 如果没有限制,似乎就不用做了...因为我们只需要贪心的选择代价较小的颜色就行了. 那么我们不妨假设染红色的代价较 ...

  4. CF704D Captain America

    http://codeforces.com/problemset/problem/704/D 题解 对于两种颜色的染色,我们可以把它看做选择问题. 比如说红色的代价小,所以我们尽可能多的染红色. 然后 ...

  5. Codeforces 474C Captain Marmot 给定4个点和各自旋转中心 问旋转成正方形的次数

    题目链接:点击打开链接 题意: 给定T表示case数 以下4行是一个case 每行2个点,u v 每次u能够绕着v逆时针转90° 问最少操作多少次使得4个u构成一个正方形. 思路: 枚举判可行 #in ...

  6. CodeForces 474C Captain Marmot (数学,旋转,暴力)

    题意:给定 4n * 2 个坐标,分成 n组,让你判断,点绕点的最少次数使得四个点是一个正方形的顶点. 析:那么就一个一个的判断,n 很小,不会超时,四个点分别从不转然后转一次,转两次...转四次,就 ...

  7. codeforces704D Captain America【上下界最大流】

    分别给行和列hash建两排点,对(x,y)坐标连x行y列的点 设红色价格低,那么就要尽量多选红色 设一个点出度为s,要求最小的最大差值为d,又,假设有流量表示选红没流量表示选蓝,那么要求就变成了这个点 ...

  8. CF704D Captain America(上下界网络流)

    传送门 题意: 二维平面给出\(n\)个点,现在可以给每个点进行染色,染红色的代价为\(r\),染蓝色的代价为\(b\). 之后会有\(m\)个限制,形式如:\(t_i\ l_i\ d_i\),当\( ...

  9. CF704D Captain America 上下界网络流

    传送门 现在相当于说每一个条件都有一个染成红色的盾牌的数量限制\([l,r]\),需要满足所有限制且染成红色的盾牌数量最小/最大. 注意到一个盾牌染成红色对于一行和一列都会产生影响.如果选中一个物品对 ...

随机推荐

  1. [Design Pattern] Factory Pattern 简单案例

    Factory Pattern , 即工厂模式,用于创建对象的场景,属于创建类的设计模式 . 下面是一个工厂模式案例. Shape 作为接口, Circle, Square, Rectangle 作为 ...

  2. D - Mayor's posters - 2528(区间覆盖)

    题意:贴海报 有一面很长的墙,大概有10000000 这么长,现有有一些海报会贴在墙上,当然贴海报的顺序是有先后的,问你当最后一张海报也贴上的时候能不能求出来在这面墙上能看到多少张不同的海报? 分析: ...

  3. HTTP学习笔记4-请求与响应结构例子

    18,HTTP消息由客户端到服务器的请求和服务器到客户端的响应组成.请求消息和响应消息都是由开始行,消息报头(可选的),空行(只有CRLF的行),消息正文(可选的)组成. 19,对于请求消息,开始行就 ...

  4. 纯CSS无hacks的跨游览器多列布局

    利用纯CSS创建一个等高多列的布局并不件易事,本教程将着重分析出现在多列布局的多个问题,然后为大家等来一个简单全游览器通吃的解决方法,不使用图片,脚本,CSS hacks并在最严格的XHTML 规范中 ...

  5. css文本超出2行就隐藏并显示省略号

    之前在网上看到过这样的代码,感觉有的时候还是挺有用的,故留个笔记. display:-webkit-box; //将对象作为弹性伸缩盒子模型显示. -webkit-box-orient:vertica ...

  6. Jquery的hover方法让鼠标经过li时背景变色

    来源地址:http://itfish.net/article/29790.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Trans ...

  7. AFNetworking (3.1.0) 源码解析 <四>

    这次主要看一下文件夹Security中的类AFSecurityPolicy----安全策略类. AFSecurityPolicy主要的作用是验证HTTPS请求证书的有效性,在iOS9之后,默认不能发送 ...

  8. [原创小知识] 如何优雅的判断 ie 版本

    之前一直不怎么做低版本ie的前端,毕竟ie的大半江山都被chrome 霸占,但大部分情况下,却还是要去兼容下那些老顽固.一切的原因,都是因为当年微软的年轻气盛,喜欢另起炉灶,真是很无语. 通常我们去h ...

  9. 跟着Android学设计模式:代理(proxy)

    代理模式 1.意图:为其它对象提供一种代理以控制对这个对象的訪问. 2.适用性: 远程代理:虚代理.保护代理:智能引用: Android源代码中用到了大量的代理设计模式.比方Context的设计,Bi ...

  10. Swift学习笔记 - 函数与闭包

    import Foundation //1.函数的定义与调用//以 func 作为前缀,返回箭头 -> 表示函数的返回类型func sayHello(name: String) -> St ...