【GDOI模拟】排列

来源:互联网 发布:嵌入式底层软件开发 编辑:程序博客网 时间:2024/06/08 07:30

Description

给你M个对1到N的排列的特征,特征有两种:
1 x y v:排列的第x个数到第y个数之间的最大值为v
2 x y v:排列的第x个数到第y个数之间的最小值为v
要求你还原出这个排列。

Solution

刷水有益身心健康。
既然是求方案,数据范围又很小,那么明显的要用把点向权值连边。
然后他每次给出范围之后再进行删边。
最后,二分图最大匹配。

Code

#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]);    }}
1 0