[ 有上下界网络流 ] Codeforces704D Captain America

假设 rb r ≤ b
把每一行作为左边的点,每一列作为右边的点建一张二分图。
每个点在对应的行列间连边,流量上限为 1 1 。这条边流量为 1 表示选红色,否则表示选蓝色。
对于左边的一个点,设右边与它相邻的点数为 s s ,它的限制为 d ,那么通过这个结点的流量 f f 满足

|2fs|d

sd2fs+d2 s − d 2 ≤ f ≤ s + d 2

右边同理。
由于 rb r ≤ b ,红色选得越多越好,所以跑一遍有上下界最大流就好了。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> abcd;
#define fi first
#define se second
const int N=200010;
const int M=5000000;
const int INF=1e9;
map<int,int>f1,f2;
abcd a[N],b[N],A[N];
int cnt1,cnt2,R,B;
int num=1,h[N],cur[N],nx[M],t[M],c[M];
int k,n,m;
int mn1[N],mn2[N],tot1[N],tot2[N];
int d[N],w[N],sum;
int dis[N],q[N],l,r;
int S,T,SS,TT;
bool fl;
inline void Add(int x,int y,int z){
    if(!z)return;
    t[++num]=y;nx[num]=h[x];h[x]=num;c[num]=z;
    t[++num]=x;nx[num]=h[y];h[y]=num;c[num]=0;
}
inline void Add(int x,int y,int l,int r){
    Add(x,y,r-l);d[x]-=l;d[y]+=l;
}
inline void Build(){
    TT=T+1;
    for(int i=S;i<=T;i++)
    if(d[i]>0)Add(SS,i,d[i]),sum+=d[i];else Add(i,TT,-d[i]);
}
inline bool Bfs(int S,int T){
    memset(dis,127,sizeof(dis));
    l=0;q[r=1]=S;dis[S]=0;
    while(++l<=r){
        int x=q[l];
        for(int i=h[x];i;i=nx[i])
        if(c[i]&&dis[t[i]]>dis[x]+1)dis[t[i]]=dis[x]+1,q[++r]=t[i];
    }
    return dis[T]<INF;
}
int Dfs(int x,int T,int f){
    if(x==T)return f;
    int sum=0,tmp;
    for(int& i=cur[x];i;i=nx[i])
    if(c[i]&&dis[t[i]]==dis[x]+1&&(tmp=Dfs(t[i],T,min(f,c[i])))){
        f-=tmp;sum+=tmp;
        c[i]-=tmp;c[i^1]+=tmp;
        if(!f)break;
    }
    return sum;
}
inline int Dinic(int s,int t){
    int Ans=0;
    while(Bfs(s,t)){
        for(int i=s;i<=t;i++)cur[i]=h[i];
        Ans+=Dfs(s,t,INF);
    }
    return Ans;
}
inline void Solve(){
    Build();
    Add(T,S,INF);
    int t=Dinic(SS,TT);
    if(t!=sum){
        puts("-1");
        return;
    }
    t=Dinic(S,T);
    printf("%I64d\n",1ll*t*R+1ll*(n-t)*B);
    for(int i=1;i<=n;i++){
        int tmp=c[w[i]];
        if(tmp^fl)putchar('b');else putchar('r');
    }
}
int main(){
    scanf("%d%d%d%d",&n,&m,&R,&B);
    if(R>B)swap(R,B),fl=1;
    for(int i=1;i<=n;i++)scanf("%d%d",&a[i].fi,&b[i].fi),a[i].se=b[i].se=i;
    sort(a+1,a+n+1);sort(b+1,b+n+1);
    for(int i=1;i<=n;i++){
        if(a[i].fi!=a[i-1].fi)f1[a[i].fi]=++cnt1;
        A[a[i].se].fi=cnt1;tot1[cnt1]++;
        if(b[i].fi!=b[i-1].fi)f2[b[i].fi]=++cnt2;
        A[b[i].se].se=cnt2;tot2[cnt2]++;
    }
    for(int i=1;i<=cnt1;i++)mn1[i]=tot1[i];
    for(int i=1;i<=cnt2;i++)mn2[i]=tot2[i];
    S=1;T=cnt1+cnt2+2;
    for(int i=1;i<=n;i++)Add(A[i].fi+1,A[i].se+cnt1+1,1),w[i]=num-1;
    for(int i=1;i<=m;i++){
        int t,l,d;
        scanf("%d%d%d",&t,&l,&d);
        if(t==1){
            if(!f1.count(l))continue;
            l=f1[l];
            mn1[l]=min(mn1[l],d);
        }else{
            if(!f2.count(l))continue;
            l=f2[l];
            mn2[l]=min(mn2[l],d);
        }
    }
    for(int i=1;i<=cnt1;i++){
        if(!mn1[i]&&tot1[i]&1){
            puts("-1");
            return 0;
        }
        Add(S,i+1,(tot1[i]-mn1[i]+1)/2,(tot1[i]+mn1[i])/2);
    }
    for(int i=1;i<=cnt2;i++){
        Add(i+cnt1+1,T,(tot2[i]-mn2[i]+1)/2,(tot2[i]+mn2[i])/2);
        if(!mn2[i]&&tot2[i]&1){
            puts("-1");
            return 0;
        }
    }
    Solve();
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值