Codefoces 793G Oleg and chess

版权声明:本文为博主原创文章,未经博主允许也可以转载。 https://blog.csdn.net/qq_35541672/article/details/85228301

目录

题意

给出一个n*n的棋盘,其中有q个矩形区域不能放棋子(但是不会隔开攻击),问最多能摆放多少个互不攻击的车
n,q<=10000(时限6.5s,而且是cf)

题解

首先考虑如果已经知道了一些可以放的单个位置,该怎么做
就一个正常的二分图建模网络流对吧
如果是知道了一些可以放的矩形区域呢?我们可以用线段树来优化建图,用两个线段树分别代表连续的x或y的一段
那么现在的问题就是怎么从不能放的得到可以放的
最直观的想法就是每个不能放的地方横竖剖开
然而这样遇到一条对角线就成功爆炸
所以要扫描线
更具体一点,是这样的
在这里插入图片描述
我们位于一个a[i]表示纵坐标为i时它最右边的值
将每个矩形拆成左右两根线段,左边那根用来更新它左边的矩形其实就是暴力找右边的a[i]连续的段,右边那根用来维护a[i]
(其实本质上来讲用左边那根维护未尝不可)
这个维护复杂度是…最坏O(n^2)的…然而CF能过…
最后再用[1,n]更新一下,得到最右边的那个矩形

em…就这样了。
然而这道题ISAP过不去…
好久没写Dinic了…
Dinic我待会再补,先放个ISAP版的代码(这个代码把ISAP改成Dinic就能过)
upd. Dinic代码已补上,同时发生了玄学错误
调了好久…一大堆调试信息懒得删了

//!CF 793G
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define lch tree[x].l
#define rch tree[x].r
using namespace std;
typedef long long ll;
const int N=1e4+5,M=4e5+5;
const int INF=0x3f3f3f3f;
struct node{//扫描线
    int x,l,r,f;
    node(){}
    node(int _x,int _l,int _r,int _f):x(_x),l(_l),r(_r),f(_f){}
}line[2*N];
bool cmp(node a,node b){
    if(a.x!=b.x)
        return a.x<b.x;
    return a.f<b.f;//同一位置更新优先
}
struct mode{
    int l,r;
}tree[N*8];
int rt1,rt2,tcnt;
struct lode{
    int u,v,cap,nxt;
}edge[M*8];
int head[M],mcnt=1;
int S,T;
int a[N];
int n,m;
void add_edge(int u,int v,int cap){
    mcnt++;
    edge[mcnt].u=u;
    edge[mcnt].v=v;
    edge[mcnt].cap=cap;
    edge[mcnt].nxt=head[u];
    head[u]=mcnt;
}
void add(int u,int v,int cap){
    add_edge(u,v,cap);
    add_edge(v,u,0);
    //printf("%d->%d %d\n",u,v,cap);
}
void Build(int &x,int fa,int l,int r,int dir){//建线段树
    x=++tcnt;
    if(fa){
        if(!dir)
            add(x,fa,INF);
        else
            add(fa,x,INF);
    }
    if(l==r)
        return ;
    int mid=(l+r)>>1;
    Build(lch,x,l,mid,dir);
    Build(rch,x,mid+1,r,dir);
}
void Build2(int x,int l,int r,int dir){//建ST到叶子
    if(l==r){
        if(dir)
            add(S,x,1);
        else
            add(x,T,1);
        return ;
    }
    int mid=(l+r)>>1;
    Build2(lch,l,mid,dir);
    Build2(rch,mid+1,r,dir);
}
void Query(int x,int l,int r,int pl,int pr,int y,int dir){//区间连边
    if(pl>pr||x==0)//这里不能省...
        return ;
    if(pl<=l&&r<=pr){
        if(!dir)
            add(x,y,INF);
        else
            add(y,x,INF);
        return ;
    }
    int mid=(l+r)>>1;
    if(pl<=mid)
        Query(lch,l,mid,pl,pr,y,dir);
    if(pr>mid)
        Query(rch,mid+1,r,pl,pr,y,dir);
}
void Insert(int x,int l,int r){//左边线段的插入
    int pos=-1,last=-1,y;
    for(int i=l;i<=r+1;i++){
        if(i<=r)
            y=a[i]+1,a[i]=-1;
        if(y!=last||i==r+1){
            if(pos!=-1){
                int z=++tcnt;
                Query(rt1,1,n,pos,i-1,z,0);
                Query(rt2,1,n,last,x,z,1);
                /*printf("%d %d %d %d\n\t",pos,last,x,z);
                for(int i=1;i<=5;i++)
                    printf("%d ",a[i]);
                puts("");*/
            }
            pos=i;
            last=y;
        }
    }
}
void Update(int x,int l,int r){//右边线段的更新
    for(int i=l;i<=r;i++)
        a[i]=x;
}
//以下是Dinic
int dist[M];
int cur[M];//当前弧
queue<int>q;
bool bfs(){
    for(int i=1;i<=tcnt;i++)
        dist[i]=-1,cur[i]=head[i];
    dist[S]=0;
    q.push(S);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].v;
            if(~dist[v]||!edge[i].cap)
                continue ;
            dist[v]=dist[u]+1;
            q.push(v);
        }
    }
    return ~dist[T];
}
int dfs(int u,int CAP){
    if(u==T||!CAP)
        return CAP;
    int flow=0;
    for(int &i=cur[u];i;i=edge[i].nxt){
        int v=edge[i].v,cap=edge[i].cap;
        if(dist[v]==dist[u]+1&&cap){
            int f=dfs(v,min(cap,CAP));
            if(!f)
                continue ;
            flow+=f;
            CAP-=f;
            if(edge[i].cap!=INF)
                edge[i].cap-=f;
            if(edge[i^1].cap!=INF)
                edge[i^1].cap+=f;
            if(!CAP)//这里注释掉就T了???
                break;
        }
    }
    return flow;
}
int Dinic(){
    int max_flow=0;
    while(bfs()){
        max_flow+=dfs(S,INF);
    }
    return max_flow;
}
void Read(int &x){
    x=0;
    char c=getchar();
    while(c<'0'||c>'9')
        c=getchar();
    while(c>='0'&&c<='9')
        x=x*10+c-'0',c=getchar();
}
int main()
{
    Read(n),Read(m);
    //scanf("%d%d",&n,&m);
    Build(rt1,0,1,n,0);
    Build(rt2,0,1,n,1);
    for(int i=1;i<=m;i++){
        int l,d,u,r;
        Read(l),Read(d),Read(r),Read(u);
        //scanf("%d%d%d%d",&l,&d,&r,&u);
        line[i]=node(l-1,d,u,1);
        line[i+m]=node(r,d,u,-1);
    }
    sort(line+1,line+m*2+1,cmp);
    for(int i=1;i<=2*m;i++){
        //printf("*%d %d %d %d\n",line[i].x,line[i].l,line[i].r,line[i].f==1?0:1);
        if(line[i].f==1)
            Insert(line[i].x,line[i].l,line[i].r);
        else
            Update(line[i].x,line[i].l,line[i].r);
    }
    Insert(n,1,n);
    S=++tcnt;
    T=++tcnt;
    Build2(rt1,1,n,1);
    Build2(rt2,1,n,0);
    int ans=Dinic();
    printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_35541672/article/details/85228301
今日推荐