题意:平面上有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. HiveServer连接优化

    引言   数据平台目前通过Hive SQL的方式提供数据分析服务,系统使用多台HiveServer(JDBCServer)接收客户端连接请求,实际使用场景中频频出现HiveServer内存消耗过多导致 ...

  2. openStack Use Orchestration module(heat) create and manage cloud resources

  3. Selenium索引

    Common Selenium各种工具比较 Selenium firefox 版本问题 Selenium IDE Selenium IDE整理 WebDriver Java 版本 Selenium开始 ...

  4. Android testing tools

    引言 发现一篇关于android 测试的培训,英文的,很全面. Android Testing Training: http://www.vogella.com/training/android/an ...

  5. 同时安装Xcode6和Xcode7导致出现N多UUID 模拟器解决办法

    [摘要:1.完整退出Xcode 和 摹拟器 2.末端中输进以下两居指令 $ sudo killall -9 com.apple.CoreSimulator.CoreSimulatorService$ ...

  6. hdu 2844

    本题的特殊性是价值与重量相等 将第i种物品分成若干件物品,其中每件物品有一个系数, 这件物品的费用和价值均是原来的费用和价值乘以这个系数. 使这些系数分别为1,2,4,…,2^(k-1),n[i]-2 ...

  7. IOS开发之Post 方式获取服务器数据

    //1.创建post方式的 参数字符串url +(NSString *)createPostURL:(NSMutableDictionary *)params { NSString *postStri ...

  8. Project Euler problem 61

    题意很明了. 然后我大概的做法就是暴搜了 先把每个几边形数中四位数的处理出来. 然后我就DFS回溯着找就行了. 比较简单吧. #include <cstdio> #include < ...

  9. Android-语言设置流程分析

    Android手机语言切换行为,是通过设置-语言和输入法-语言来改变手机的语言,其实这个功能很少被用户使用.     以Android5.1工程源码为基础,从设置app入手来分析和学习语言切换的过程: ...

  10. jquery中prop()方法和attr()方法的区别(转)

    jquery1.6中新加了一个方法prop(),一直没用过它,官方解释只有一句话:获取在匹配的元素集中的第一个元素的属性值. 官方例举的例子感觉和attr()差不多,也不知道有什么区别,既然有了pro ...