给你M个对1到N的排列的特征,特征有两种:
1 x y v:排列的第x个数到第y个数之间的最大值为v
2 x y v:排列的第x个数到第y个数之间的最小值为v
要求你还原出这个排列。
刷水有益身心健康。
既然是求方案,数据范围又很小,那么明显的要用把点向权值连边。
然后他每次给出范围之后再进行删边。
最后,二分图最大匹配。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=405;
int i,j,k,l,t,n,m,num,S,T,aa,b,c,dd,ans[maxn],po;
//int first[maxn],next[maxn],last[maxn],chang[maxn],fan[maxn];
int a[maxn][maxn],p[maxn],d[maxn];
bool bz[maxn];
bool bfs(){
int data[maxn],head=0,tail=1,now,i,ber;
memset(data,0,sizeof(data));
memset(d,0,sizeof(d));d[S]=1;
ber=d[0];
data[1]=S;
while(head<tail){
now=data[++head];
fo(i,S,T){
if(!d[i]&&a[now][i]>0){
d[i]=d[now]+1;
data[++tail]=i;
}
}
}
return d[T]!=0;
}
int dinic(int x,int y){
int i,j,k=0,l=0;
if(x==T){
return y;
}
fo(i,S,T){
if(d[x]+1==d[i]&&a[x][i]>0){
k=dinic(i,min(a[x][i],y));
if(k){
l+=k;
a[x][i]-=k;a[i][x]+=k;
y-=k;
if(y==0)break;
}
}
}
if(l==0)d[x]=-1;
return l;
}
int main(){
scanf("%d%d",&n,&m);
S=0;T=2*n+1;
fo(i,1,n)fo(j,n+1,2*n)a[i][j]=1;
fo(i,1,n)a[S][i]=1,a[i+n][T]=1;
fo(i,1,m){
scanf("%d%d%d%d",&aa,&b,&c,&dd);
if(aa==1){
fo(j,b,c){
fo(k,dd+1,n)a[j][k+n]=-100;
}
}
else{
fo(j,b,c){
fo(k,1,dd-1)a[j][k+n]=-100;
}
}
fo(j,1,b-1)a[j][dd+n]=-100;fo(j,c+1,n)a[j][dd+n]=-100;
}
while(bfs())po+=dinic(S,n);
fo(i,1,n){
bool az=0;
fo(j,n+1,2*n){
if(a[i][j]==0){az=1;break;}
}
if(!az){
printf("-1\n");return 0;
}
else{
ans[i]=j-n;
}
}
fo(i,1,n){
printf("%d ",ans[i]);
}
}