1. 程式人生 > >CF704D Captain America 上下界網路流

CF704D Captain America 上下界網路流

題目大意:
給你nn個點,座標為(xi,yi)(x_i,y_i),每個點可染成紅色或者藍色,代價分別為RRBB
有若干限制,每個限制使得某一行或者某一列的紅色和藍色的點數的差小於等於did_i
問最小染色代價,有解則輸出解,否則輸出1-1

分析:
假設某一行有ss個點(列同理),假設最小限制為dd,紅色點數為RR,藍色點數為BB,那麼有
R+B=sR+B=s
RB<=d|R-B|<=d
也就是
2Rs<=d|2R-s|<=d

=d
sd2<=R<=s+d2\lceil\frac{s-d}{2}\rceil<=R<=\lfloor\frac{s+d}{2}\rfloor
也就是說每個點的紅色點有一個限制,考慮使用上下界網路流。
首先拆成兩列點,第一列表示橫座標,第二列表示縱左邊,一個點(x,y)(x,y)就是一條從xxyy的流量為11的邊,當然這個要離散化,然後SS向所有左邊的點連一條流量上述限制的點,右邊的點向TT同理。
我們假設(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");
        }
    }
}