码迷,mamicode.com
首页 > 其他好文 > 详细

51nod 1336 RMQ逆问题

时间:2016-08-22 18:06:08      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:

RMQ问题是一类区间最值问题,这里给出一个特殊的RMQ问题,初始给定一个n长的排列P,注:n长排列是指有1~n这n个整数构成的一个序列每个整数恰好出现一次。并对这个排列P进行M次查询操作,每次查询形如Query(L,R),每次查询返回排列P中位置在区间[L,R]上所有数中最大的那个数,其中位置的下标从1开始。例如排列P = {3,1,4,2,5},
那么Query(1,2) = max{3,1}=3,Query(2,4)=max{1,4,2}=4。由于RMQ问题对大家来说实在是太简单了,所以这题要求大家求解一个RMQ的逆问题,即给你排列的长度n,以及M次查询的问题及其结果三元组(Li,Ri,Qi),即Query(Li,Ri)=Qi,询问符合这M次查询的n长排列是否存在。若存在输出“Possible”;否则输出“Impossible”。
Input
多组测试数据,第一行一个整数T,表示测试数据数量,1<=T<=5
之后有T组结构相同的数据:
每组数据的第一行有两个整数n与M,其中1<=n<=10^9(即1,000,000,000),1<=M<=50
之后会有M行,每行表示一个三元组Li,Ri,Qi,其中1<=Li<=Ri<=n,1<=Qi<=n
Output
每组数据输出一行,即“Possible”或“Impossible”不含引号

对于一个询问(L,R,Q),能得到的信息是(Q,n]中的数只能在[1,L)或(R,n],Q只能在[L,R]

因此离散化之后可以转化为最大流,左边的点代表每个数值/数值区间,右边的点代表每个区间,之间连边inf代表此数值可以在此区间内,源点到左边的点连边限制每个数值/数值区间中数值的个数,右边的点连边到汇点限制每个区间内数值的个数,当且仅当最大流为n时有解

#include<cstdio>
#include<algorithm>
const int N=100000,inf=0x3f3f3f3f;
int es[N],enx[N],ev[N],e0[N],ep;
int h[N],q[N],S,T;
inline void adde(int a,int b,int c){
    es[ep]=b;enx[ep]=e0[a];ev[ep]=c;e0[a]=ep++;
    es[ep]=a;enx[ep]=e0[b];ev[ep]=0;e0[b]=ep++;
}
bool bfs(){
    int ql=0,qr=0;
    for(int i=0;i<=T;i++)h[i]=0;
    h[S]=1;q[qr++]=S;
    while(ql!=qr){
        int w=q[ql++];
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(!h[u]&&ev[i]){
                h[u]=h[w]+1;
                q[qr++]=u;
            }
        }
    }
    return h[T];
}
int dfs(int w,int f){
    if(w==T)return f;
    int c,u,used=0;
    for(int i=e0[w];i;i=enx[i]){
        u=es[i];
        if(h[u]!=h[w]+1||!ev[i])continue;
        c=f-used;
        if(c>ev[i])c=ev[i];
        c=dfs(u,c);
        used+=c;
        ev[i]-=c;
        ev[i^1]+=c;
        if(used==f)return f;
    }
    if(!used)h[w]=0;
    return used;
}
int qs[53][3],xs[107],ps[107],xp,pp;
bool d[107][107];
int main(){
    int _T,n,q;
    for(scanf("%d",&_T);_T;_T--){
        scanf("%d%d",&n,&q);
        for(int i=0;i<q;i++)scanf("%d%d%d",qs[i],qs[i]+1,qs[i]+2);
        xp=pp=0;
        xs[xp++]=1;
        xs[xp++]=n+1;
        ps[pp++]=1;
        ps[pp++]=n+1;
        for(int i=0;i<q;i++){
            xs[xp++]=qs[i][2];
            xs[xp++]=qs[i][2]+1;
            ps[pp++]=qs[i][0];
            ps[pp++]=qs[i][1]+1;
        }
        std::sort(xs,xs+xp);
        xp=std::unique(xs,xs+xp)-xs;
        std::sort(ps,ps+pp);
        pp=std::unique(ps,ps+pp)-ps;
        for(int i=0;i<xp;i++)for(int j=0;j<pp;j++)d[i][j]=1;
        for(int i=0;i<q;i++){
            for(int j=0;j<xp-1;j++){
                if(xs[j]>qs[i][2]){
                    for(int k=0;k<pp-1;k++)if(qs[i][0]<=ps[k]&&ps[k]<=qs[i][1]){
                        d[j][k]=0;
                    }
                }else if(xs[j]==qs[i][2]){
                    for(int k=0;k<pp-1;k++)if(qs[i][0]>ps[k]||ps[k]>qs[i][1]){
                        d[j][k]=0;
                    }
                }
            }
        }
        S=xp+pp+1;T=S+1;
        for(int i=1;i<=T;i++)e0[i]=0;
        ep=2;
        for(int i=0;i<xp-1;i++)adde(S,i+1,xs[i+1]-xs[i]);
        for(int i=0;i<pp-1;i++)adde(xp+i+1,T,ps[i+1]-ps[i]);
        for(int i=0;i<xp-1;i++)for(int j=0;j<pp-1;j++)if(d[i][j])adde(i+1,xp+j+1,n);
        int ans=0;
        while(bfs())ans+=dfs(S,inf);
        puts(ans==n?"Possible":"Impossible");
    }
    return 0;
}

 

51nod 1336 RMQ逆问题

标签:

原文地址:http://www.cnblogs.com/ccz181078/p/5796306.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!