Codeforces 704D Captain America

题意:平面上有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=400050,maxm=3000000;

struct edge{

  int to,next,w,num;

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

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

  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=0;first[b]=len++;

}

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

bool bfs(){

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

  while(head!=tail){

    int x=q[head++];

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

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

        vis[lst[pt].to]=T;dis[lst[pt].to]=dis[x]+1;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=0,a;

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

    _first[x]=pt;

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

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

      if(flow==lim)return flow;

    }

  }

  return flow;

}

int dinic(){

  int ans=0,x;

  while(bfs())

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

  return ans;

}

void del(int x){

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

}

int totflow[maxn];

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

  int ss=t+1,tt=t+2;

  int sum=0;

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

    if(totflow[i]<0){

      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 -1;

  }else{//return 0;

    int ans0=lst[len-1].w;

    lst[len-1].w=lst[len-2].w=0;

    del(ss);del(tt);

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

    return ans0-dinic();

  }

}

void Add(int a,int b,int lo,int hi,int num=0){//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=0,old=-1,cnt=0;

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

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

  }

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

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

  }

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

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

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

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

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

    }

    val[seq[i]]=cnt;

  }

  tot=0;

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

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

  }

  for(int i=1;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,-1,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=1;i<=n;++i){

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

  }

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

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

  }

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

  //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=1;i<=n;++i)cntx[x[i]]++,cnty[y[i]]++;

  ll ans=r*1LL*n;

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

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

  }

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

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

  }

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

    if(typ[i]==1){

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

    }else{

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

    }

  }

  s=0;t=totx+toty+1;

  bool no_solution=false;

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

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

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

  }//printf("!");

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

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

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

  }//printf("!");

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

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

  }//printf("!");

  if(no_solution){

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

  }

  int flow=bound_flow();

  if(flow!=-1){

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

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

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

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

          res[lst[pt].num]=1;

        }

      }

    }//printf("?");

    if(reversed){

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

    }else{

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

    }printf("\n");

  }

  return 0;

}

 

 

posted @ 2017-01-09 17:51  liu_runda  阅读(396)  评论(0编辑  收藏  举报
偶然想到可以用这样的字体藏一点想说的话,可是并没有什么想说的. 现在有了:文化课好难