洛谷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 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; }