51nod 1336 RMQ逆问题

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;
}
时间: 2024-10-12 04:33:24

51nod 1336 RMQ逆问题的相关文章

51Nod 1174 区间中最大的数(RMQ)

1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 5 using namespace std; 6 const int maxn = 10000 + 5; 7 int a[maxn]; 8 int f[maxn][15]; 9 10 void rmq(int cnt){ 11 memset(f, 0, sizeof(f)); 12 for (int i = 1; i <= cnt

51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)

题目链接 \(Description\) 给定一棵树.每次询问给定\(a\sim b,c\sim d\)两个下标区间,从这两个区间中各取一个点,使得这两个点距离最远.输出最远距离. \(n,q\leq10^5\). \(Solution\) 一个集合直径的两端点,在被划分为两个集合后一定是两个集合直径的四个端点中的两个. 即假设将\(S\)分为两个集合后,另外两个集合的直径的两端点分别为a,b和c,d,那么\(S\)集合的直径的两端点一定是a,b,c,d中的两个. 证明类似树的直径. 所以信息可

51nod1174(RMQ)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1174 题意:中文题诶- 思路:RMQ模板题 关于RMQ: http://blog.csdn.net/liang5630/article/details/7917702 代码: 1 #include <bits/stdc++.h> 2 #define MAXN 10010 3 using namespace std; 4 5 int dp[MAXN][30]

51Nod - 1102 面积最大的矩形

51Nod - 1102 面积最大的矩形 有一个正整数的数组,化为直方图,求此直方图包含的最大矩形面积.例如 2,1,5,6,2,3,对应的直方图如下: 面积最大的矩形为5,6组成的宽度为2的矩形,面积为10. Input 第1行:1个数N,表示数组的长度(0 <= N <= 50000) 第2 - N + 1行:数组元素A[i].(1 <= A[i] <= 10^9) Output 输出最大的矩形面积 Input示例 6 2 1 5 6 2 3 Output示例 10 题解: (

51nod 1201 整数划分(dp)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1201 题解:显然是一道dp,不妨设dp[i][j]表示数字i分成j个一共有几种分法. 那么转移方程式为: dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] 表示将i - 1划分为j个数,然后j个数都+1 还是不重复,将i - 1划分为j - 1个数,然后j - 1个数都+1,再加上1这个数. 然后就是j的范围要知道1+2+

dutacm.club 1094: 等差区间(RMQ区间最大、最小值,区间GCD)

1094: 等差区间 Time Limit:5000/3000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)Total Submissions:655   Accepted:54 [Submit][Status][Discuss] Description 已知一个长度为 n 的数组 a[1],a[2],-,a[n],我们进行 q 次询问,每次询问区间 a[l],a[l+1],-,a[r?1],a[r] ,数字从小到大

RMQ问题再临

RMQ问题再临 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 终于,小Hi和小Ho踏上了回国的旅程.在飞机上,望着采购来的特产——小Hi陷入了沉思:还记得在上上周他们去超市的时候,前前后后挑了那么多的东西,都幸运的没有任何其他人(售货员/其他顾客)来打搅他们的采购过程.但是如果发生了这样的事情,他们的采购又会变得如何呢? 于是小Hi便向小Ho提出了这个问题:假设整个货架上从左到右摆放了N种商品,并且依次标号为1到N,每次小Hi都给出一段区间[L, R],小Ho要做

[bzoj3489]A simple rmq problem

本题既不是rmq也不会simple(对我这种蒟蒻而言) 一开始只能想到树套树套树TAT然后看了看数据范围果断滚去膜拜题解. 然后才知道预先排序一下可以弄掉一个log.不过得写可持久化线段树套可持久化线段树.. 然后愉悦的开码了...感人的是竟然不用调...更感人的是交上去直接tle了. 然后从网上找了别人的代码(方法一样)发现同样的数据我要跑6s+..标称只要2s+.. 之后各种卡常还是慢了一倍TAT...最后自己写个max函数就和标程一样快了TAT这几天怎么总是出些奇怪的状况QAQ. 本来故事

CodeForces 514D R2D2 and Droid Army RMQ+二分

题目链接:点击打开链接 题意:给定n m k 下面是n*m的矩阵 最多可以操作k次,每次操作可以使任意一列上所有的数 -= 1,( 0还是0) 要求得到连续最多的行数(每行里的整数都为0),输出任意一个方案(在每一列上操作的次数) 思路: 把每列单独考虑 枚举每行,二分找这行往下最多能清空的行数, RMQ维护一列的最大值. import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWr