CF704D Captain America 上下界网络流

题目大意:
给你 n n n个点,坐标为 ( x i , y i ) (x_i,y_i) (xi,yi),每个点可染成红色或者蓝色,代价分别为 R R R B B B
有若干限制,每个限制使得某一行或者某一列的红色和蓝色的点数的差小于等于 d i d_i di
问最小染色代价,有解则输出解,否则输出 − 1 -1 1

分析:
假设某一行有 s s s个点(列同理),假设最小限制为 d d d,红色点数为 R R R,蓝色点数为 B B B,那么有
R + B = s R+B=s R+B=s
∣ R − B ∣ &lt; = d |R-B|&lt;=d RB<=d
也就是
∣ 2 R − s ∣ &lt; = d |2R-s|&lt;=d 2Rs<=d
⌈ s − d 2 ⌉ &lt; = R &lt; = ⌊ s + d 2 ⌋ \lceil\frac{s-d}{2}\rceil&lt;=R&lt;=\lfloor\frac{s+d}{2}\rfloor 2sd<=R<=2s+d
也就是说每个点的红色点有一个限制,考虑使用上下界网络流。
首先拆成两列点,第一列表示横坐标,第二列表示纵左边,一个点 ( x , y ) (x,y) (x,y)就是一条从 x x x y y y的流量为 1 1 1的边,当然这个要离散化,然后 S S S向所有左边的点连一条流量上述限制的点,右边的点向 T T T同理。
我们假设 ( x , y ) (x,y) (x,y)这条边有流量,则选择代价小的一个,否则选择代价大的。这样相当于跑有限制的最大流,输出方案时判断即可。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#define LL long long

const int maxn=1e5+7;
const int maxe=3e6+7;
const LL inf=1e17;

using namespace std;

LL n,m,R,B,s,t,op,l,d,ns,nt,cnt;
LL x[maxn],y[maxn],sx[maxn],sy[maxn],mn[maxn*2],mx[maxn*2],num[maxn],deg[maxn*2];
LL ls[maxn*2],dis[maxn*2];

queue <LL> q;

struct edge{
    LL y,w,op,next;
}g[maxe];

struct rec{
    LL x,y;
}a[maxn];

void add(LL x,LL y,LL w)
{
    g[++cnt]=(edge){y,w,cnt+1,ls[x]};
    ls[x]=cnt;
    g[++cnt]=(edge){x,0,cnt-1,ls[y]};
    ls[y]=cnt;
}

bool bfs()
{
    while (!q.empty()) q.pop();
    for (LL i=0;i<=nt;i++) dis[i]=inf;
    dis[ns]=0;
    q.push(ns);
    while (!q.empty())
    {
        LL x=q.front();
        q.pop();
        for (LL i=ls[x];i>0;i=g[i].next)
        {
            LL y=g[i].y;
            if ((g[i].w) && (dis[y]>dis[x]+1))
            {
                dis[y]=dis[x]+1;
                if (y==nt) return 1;
                q.push(y);
            }
        }
    }
    return 0;
}

LL dfs(LL x,LL maxf)
{
    if ((x==nt) || (maxf==0)) return maxf;
    LL ret=0;
    for (LL i=ls[x];i>0;i=g[i].next)
    {
        LL y=g[i].y;
        if ((dis[y]==dis[x]+1) && (g[i].w))
        {
            LL f=dfs(y,min(maxf-ret,g[i].w));
            if (!f) dis[y]=0;
            ret+=f;
            g[i].w-=f;
            g[g[i].op].w+=f;
            if (ret==maxf) break;
        }
    }
    return ret;
}

LL dinic()
{
    LL flow=0;
    while (bfs()) 
      flow+=dfs(ns,inf);
    return flow;
}

int main()
{
    scanf("%lld%lld",&n,&m);
    scanf("%lld%lld",&R,&B);
    for (LL i=1;i<=n;i++)
    {
        scanf("%lld%lld",&a[i].x,&a[i].y);
        x[i]=a[i].x;
        y[i]=a[i].y;
    }
    sort(x+1,x+n+1);
    sort(y+1,y+n+1);
    LL size1=unique(x+1,x+n+1)-x-1,size2=unique(y+1,y+n+1)-y-1;
    s=0,t=size1+size2+1;
    for (LL i=1;i<=n;i++)
    {
        LL xx=lower_bound(x+1,x+size1+1,a[i].x)-x;
        LL yy=lower_bound(y+1,y+size2+1,a[i].y)-y;
        add(xx,yy+size1,1);
        sx[xx]++,sy[yy]++,num[i]=cnt-1;
    }
    for (LL i=1;i<=size1+size2;i++) mn[i]=0,mx[i]=n;
    for (LL i=1;i<=m;i++)
    {
        scanf("%lld%lld%lld",&op,&l,&d);
        if (op==1)
        {
            LL p=lower_bound(x+1,x+size1+1,l)-x;
            if ((x[p]!=l) || (d>=sx[p])) continue;
            LL L=(sx[p]-d+1)/2,R=sx[p]-L;
            if (L>R)
            {
                printf("-1");
                return 0;
            }
            mx[p]=min(mx[p],R);
            mn[p]=max(mn[p],L);
        }
        else
        {
            LL p=lower_bound(y+1,y+size2+1,l)-y;
            if ((y[p]!=l) || (d>=sy[p])) continue;
            LL L=(sy[p]-d+1)/2,R=sy[p]-L;
            if (L>R)
            {
                printf("-1");
                return 0;
            }
            mx[p+size1]=min(mx[p+size1],R);
            mn[p+size1]=max(mn[p+size1],L);
        }
    }	
    for (LL i=1;i<=size1;i++)
    {
        deg[s]-=mn[i];
        deg[i]+=mn[i];
        add(s,i,min(sx[i],mx[i])-mn[i]);
    }
    for (LL i=size1+1;i<=size1+size2;i++)
    {
        deg[i]-=mn[i];
        deg[t]+=mn[i];
        add(i,t,min(sy[i-size1],mx[i])-mn[i]);
    }
    LL nowcnt=cnt,S=t+1,T=t+2;	
    add(t,s,inf);
    LL sum=0;
    for (LL i=s;i<=t;i++)
    {
        if (deg[i]<0) add(i,T,-deg[i]);
        else if (deg[i]>0) add(S,i,deg[i]),sum+=deg[i];
    }	
    ns=S,nt=T;
    if (dinic()!=sum)
    {
        printf("-1");
        return 0;
    }
    for (LL i=nowcnt+1;i<=cnt;i++) g[i].w=0;
    ns=s,nt=t;
    dinic();
    LL ans=0;
    for (int i=1;i<=n;i++)
    {
        if (!g[num[i]].w) ans+=min(B,R);
                     else ans+=max(B,R);
    }
    printf("%lld\n",ans);
    for (LL i=1;i<=n;i++)
    {
        if (!g[num[i]].w)
        {
            if (B<R) printf("b");
                else printf("r");
        }
        else
        {
            if (B<R) printf("r");
                else printf("b");
        }
    }
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值