【GDOI模拟】排列

Description

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

Solution

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

Code

#include
#include
#include
#include
#include
#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(headif(!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]);
    }
}

你可能感兴趣的:(网络流,二分图最大匹配,GDOI)