洛谷P8299 题解

题意

你需要构造一个 $1∼N$ 的排列,满足 $M$ 个要求,要求形式是给出 $l,r$ 中的最大值或最小值。

思路

不难看出,这是一个二分图匹配问题。我们要给每个位置匹配一个数。那么怎么建边呢?我们发现根据题目给出的要求,好像不是很好直接看出每个位置能匹配哪些数。不过正难则反,题目给出的要求是很容易看出每个位置不能匹配哪些数的。显然如果题目给出 $[l,r]$ 中最小的数是 $x$,那么这些位置不能与任何小于 $x$ 的数匹配。大于同理。

这样就够了吗?其实是有问题的。我们这样无法保证 $x$ 这个数一定被分配到 $[l,r]$ 这个区间里。所以我们还有让所有不在 $[l,r]$ 的数都不能匹配到 $x$,这样就保证满足题目条件了。

至于二分图匹配部分,可以用匈牙利,当然我用的 Dinic。

丑陋的代码(跑得贼慢)

#include <bits/stdc++.h>
#define int long long
using namespace std;
bool ok[205][205];
int n,m,cnt=1,lst[415],s,t,inf=0x3f3f3f3f,now[415],dep[415],flow,seat[415]; 
struct edge{
    int f,t,val,lst;
    edge(int f=0,int t=0,int val=0,int lst=0):
        f(f),t(t),val(val),lst(lst){}; 
}e[400005];
void add(int u,int v,int w){
    e[++cnt]=edge(u,v,w,lst[u]);lst[u]=cnt;
    e[++cnt]=edge(v,u,0,lst[v]);lst[v]=cnt;
}
bool bfs(){
    memset(dep,-1,sizeof(dep));
    dep[s]=0;
    queue<int> q;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        now[u]=lst[u];
        for(int i=lst[u];i;i=e[i].lst){
            int v=e[i].t;
            if(dep[v]==-1&&e[i].val){
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    } 
    return dep[t]!=-1;
}
int dfs(int u,int in){
    if(u==t)return in;
    int out=0;
    for(int i=now[u];i;i=e[i].lst){
        now[u]=i;
        int v=e[i].t;
        if(dep[v]==dep[u]+1&&e[i].val){
            int go=dfs(v,min(in,e[i].val));
            in-=go,out+=go;
            e[i].val-=go,e[i^1].val+=go;
            if(!in)break;
        }
    }
    if(!out)dep[u]=-1;
    return out;
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int op,u,v,x;
        cin>>op>>u>>v>>x;
        if(op==1){
            for(int j=u;j<=v;j++){
                for(int k=x+1;k<=n;k++){
                    ok[j][k]=1;
                }
            }
            for(int j=1;j<u;j++){
                ok[j][x]=1;
            }
            for(int j=v+1;j<=n;j++){
                ok[j][x]=1;
            }
        }
        else{
            for(int j=u;j<=v;j++){
                for(int k=1;k<x;k++){
                    ok[j][k]=1;
                }
            }
            for(int j=1;j<u;j++){
                ok[j][x]=1;
            }
            for(int j=v+1;j<=n;j++){
                ok[j][x]=1;
            }
        }
    }
    s=0,t=n*2+1;
    for(int i=1;i<=n;i++){
        add(s,i,1);
        add(i+n,t,1);
        for(int j=1;j<=n;j++){
            if(!ok[i][j])add(i,j+n,1);
        }
    }
    while(bfs()){
        flow+=dfs(s,inf);
    }
    if(flow!=n)puts("-1");
    else{
        for(int i=2;i<=cnt;i++){
            if(!e[i].val&&e[i^1].val&&e[i].f<=n&&e[i].f&&e[i].t>n&&e[i].t!=t){
                seat[e[i].f]=e[i].t;
            }
        }
        for(int i=1;i<=n;i++)cout<<seat[i]-n<<' ';
    }
    return 0;
}