Codeforces Round #576 (Div. 1) E. Rectangle Painting 2

链接

https://codeforces.com/contest/1198/problem/E

题解

先离散化,把矩形拆成一块一块的
注意离散化有技巧,要用左闭右开区间
然后建一张图,从左往右依次是:源点,行结点,列结点,汇点
一个区块对应的行和列连边流量是无穷,原点向行节点连边,流量是这个行结点对应实际的行数,列结点向汇点连边,流量是这个列结点对应实际的列数
最小割就是答案

代码

#include <bits/stdc++.h>
#define maxn 100010
#define maxe 500010
#define linf (1ll<<60)
#define iinf 0x3f3f3f3f
#define eps 1e-8
#define cl(x) memset(x,0,sizeof(x))
#define mod 998244353ll
using namespace std;
struct Graph2
{
    int head[maxn], next[maxe], to[maxe], w[maxe], c[maxe], tot;
    void clear(int N)
    {
        int i;
        for(i=1;i<=N;i++)head[i]=0;
        for(i=2;i<=tot;i++)next[i]=0;
        tot=1;
    }
    void add(int a, int b, int ww, int cc){to[++tot]=b;next[tot]=head[a];w[tot]=ww;c[tot]=cc;head[a]=tot;}
    void adde(int a, int b, int ww,int cc){add(a,b,ww,cc);add(b,a,-ww,0);}
}G;
struct ISAP
{
    int S, T, last[maxn], d[maxn], num[maxn], Exit;
    void init(int N)
    {
        for(int i=1;i<=N;i++)d[i]=num[i]=0;
        num[0]=N;
        Exit=0;
    }
    int dfs(Graph2& G, int pos, int in)
    {
        int flow=0, t;
        if(pos==T)return in;
        for(int &p=last[pos];p;p=G.next[p])
            if(G.c[p] and d[G.to[p]]+1==d[pos])
            {
                flow+= t=dfs(G,G.to[p],min(in-flow,G.c[p]));
                G.c[p]-=t, G.c[p^1]+=t;
                if(Exit or in==flow)return flow;
            }
        Exit=--num[d[pos]]==0;
        ++num[++d[pos]];
        last[pos]=G.head[pos];
        return flow;
    }
    int maxflow(Graph2& G)
    {
        int ans(0);
        while(!Exit)ans+=dfs(G,S,iinf);
        return ans;
    }
}isap;
struct Lisan
{
    int tmp[maxn], tot;
    void clear(){tot=0;}
    void insert(int x){tmp[++tot]=x;}
    void run()
    {
        sort(tmp+1,tmp+tot+1);
        tot=unique(tmp+1,tmp+tot+1)-tmp-1;
    }
    void lisan(int *a, int len)
    {
        for(int i=1;i<=len;i++)a[i]=lower_bound(tmp+1,tmp+tot+1,a[i])-tmp;
    }
    int lisan(int x)
    {
        return lower_bound(tmp+1,tmp+tot+1,x)-tmp;
    }
}row, col;
int n, m, X1[maxn], Y1[maxn], X2[maxn], Y2[maxn];
int main()
{
    int i, j, k;
    cin>>n>>m;
    for(i=1;i<=m;i++)
    {
        cin>>X1[i]>>Y1[i]>>X2[i]>>Y2[i];
        row.insert(X1[i]), row.insert(X2[i]+1);
        col.insert(Y1[i]), col.insert(Y2[i]+1);
    }
    row.run(), col.run();
    isap.S=row.tot+col.tot+10;
    isap.T=isap.S+1;
    G.clear(isap.T);
    for(i=1;i<row.tot;i++)G.adde(isap.S,i,0,row.tmp[i+1]-row.tmp[i]);
    for(i=1;i<col.tot;i++)G.adde(row.tot+i,isap.T,0,col.tmp[i+1]-col.tmp[i]);
    for(i=1;i<=m;i++)
    {
        for(j=row.lisan(X1[i]);row.tmp[j]<X2[i]+1;j++)
            for(k=col.lisan(Y1[i]);col.tmp[k]<Y2[i]+1;k++)
                G.adde(j,row.tot+k,0,iinf);
    }
    isap.init(isap.T);
    cout<<isap.maxflow(G);
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值