题解:线段树。
对于每一列扫一遍,对于以第i行为起点合法的序列最多能维持到哪一行。
线段树的区间修改,点查询。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100003
using namespace std;
int n,m,tr[N*4],delta[N*4];
void pushdown(int now)
{
if (delta[now]) {
delta[now<<1]=max(delta[now<<1],delta[now]);
delta[now<<1|1]=max(delta[now<<1|1],delta[now]);
tr[now<<1]=max(tr[now<<1],delta[now]);
tr[now<<1|1]=max(tr[now<<1|1],delta[now]);
delta[now]=0;
}
}
void qjchange(int now,int l,int r,int ll,int rr,int v)
{
if (ll<=l&&r<=rr) {
tr[now]=max(tr[now],v);
delta[now]=max(delta[now],v);
return;
}
int mid=(l+r)/2;
pushdown(now);
if (ll<=mid) qjchange(now<<1,l,mid,ll,rr,v);
if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr,v);
}
int find(int now,int l,int r,int x)
{
if (l==r) return tr[now];
int mid=(l+r)/2;
pushdown(now);
if (x<=mid) return find(now<<1,l,mid,x);
else return find(now<<1|1,mid+1,r,x);
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
int a[n+2][m+2];
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
for (int j=1;j<=m;j++){
int l,r; l=r=1;
for (int i=2;i<=n;i++)
if (a[i][j]<a[i-1][j]){
qjchange(1,1,n,l,r,r);
//cout<<l<<" "<<r<<endl;
l=r=i;
}
else r++;
qjchange(1,1,n,l,r,r);
//cout<<l<<" "<<r<<endl;
}
int q; scanf("%d",&q);// cout<<q<<endl;
for (int i=1;i<=q;i++) {
int l,r; scanf("%d%d",&l,&r);// cout<<l<<" "<<r<<endl;
int t=find(1,1,n,l);// cout<<t<<endl;
if (t>=r) printf("Yes\n");
else printf("No\n");
}
}