zoukankan      html  css  js  c++  java
  • 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
    ");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
    ",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
    ",x[i],y[i]);
    
      //for(int i=1;i<=m;++i)printf("%d %d %d
    ",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
    ");return 0;
    
      }
    
      int flow=bound_flow();
    
      if(flow!=-1){
    
        printf("%lld
    ",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("
    ");
    
      }
    
      return 0;
    
    }
    
     
  • 相关阅读:
    从Java小白到收获BAT等offer,分享我这两年的经验和感悟
    我的Java秋招面经大合集
    从零基础到拿到网易Java实习offer,我做对了哪些事
    设计模式常见面试知识点总结(Java版)
    如何才能够系统地学习Java并发技术?
    这些喜闻乐见的Java面试知识点,你都掌握了吗?
    Java集合类常见面试知识点总结
    用大白话告诉你 :Java 后端到底是在做什么?
    16-使用Selenium模拟浏览器抓取淘宝商品美食信息
    15-分析Ajax请求并抓取今日头条街拍美图
  • 原文地址:https://www.cnblogs.com/liu-runda/p/6266105.html
Copyright © 2011-2022 走看看