Description
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。
Input
第一行两个数N,Q,表示矩阵大小和询问组数;
接下来N行N列一共N*N个数,表示这个矩阵;
再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。
接下来N行N列一共N*N个数,表示这个矩阵;
再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。
Output
对于每组询问输出第K小的数。
Sample Input
2 2
2 1
3 4
1 2 1 2 1
1 1 2 2 3
2 1
3 4
1 2 1 2 1
1 1 2 2 3
Sample Output
1
3
3
HINT
矩阵中数字是109以内的非负整数;
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。
据说正解是整体二分,然而看了半天并没有看懂,最后选择了分块
首先将矩阵里的数字排序,然后每次插size个,插入后暴力扫一遍询问,如果有询问的区间在本次操作中数字个数大于了k,就说明查询的k值在刚刚插入的
size个数中,此时再暴力倒序扫一遍刚刚的size个数字就好了,二位前缀和维护矩阵内数字的个数,链表维护询问即可
代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#define maxn 505
#define maxq 60005
using namespace std;
inline void read(int& x)
{ char c=getchar();x=0;int y=1;
while(c<'0'||c>'9'){if(c=='-') y=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
x*=y;
}
template<typename T>inline T m_min(T x,T y){return x<y?x:y;}
int n,q,sum[maxn][maxn],sz,ans[maxq],done,cnt,pre[maxq],nex[maxq],A[maxn][maxn];
struct query
{ int x1,x2,y1,y2,k;
query(int a=0,int b=0,int c=0,int d=0,int e=0):x1(a),x2(b),y1(c),y2(d),k(e){}
}Q[maxq];
struct node
{ int x,y,v;
node(int x=0,int y=0,int z=0):x(x),y(y),v(z){}
friend bool operator<(const node& a,const node& b){return a.v<b.v;}
}matrix[maxn*maxn];
int main()
{ read(n);read(q);int x,y,a,b,c;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{ read(x);
matrix[++cnt]=node(i,j,x);
}
for(int i=1;i<=q;++i)
{ read(x);read(y);read(a),read(b);read(c);
Q[i]=query(x,a,y,b,c);
pre[i]=i-1;nex[i]=i+1;
}
nex[0]=1;
sort(matrix+1,matrix+cnt+1);
register int i,j,k,lef,rig,_,__;
int now;
for(i=1;i<=n;++i)
{ lef=(i-1)*n+1;rig=lef+n-1;
for(j=lef;j<=rig;++j)
A[matrix[j].x][matrix[j].y]=1;
for(_=1;_<=n;++_)
for(__=1;__<=n;++__)
sum[_][__]=sum[_][__-1]+sum[_-1][__]-sum[_-1][__-1]+A[_][__];
for(j=nex[0];j<=q;j=nex[j])
{ now=sum[Q[j].x2][Q[j].y2]-sum[Q[j].x2][Q[j].y1-1]-sum[Q[j].x1-1][Q[j].y2]+sum[Q[j].x1-1][Q[j].y1-1];
if(now>=Q[j].k)
for(int l=rig;l>=lef;--l)
if(matrix[l].x>=Q[j].x1&&matrix[l].x<=Q[j].x2&&matrix[l].y>=Q[j].y1&&matrix[l].y<=Q[j].y2)
{ --now;
if(now<Q[j].k)
{ ans[j]=matrix[l].v;++done;
nex[pre[j]]=nex[j];pre[nex[j]]=pre[j];
break;
}
}
}
if(done==q) break;
}
for(int i=1;i<=q;++i) printf("%d\n",ans[i]);
return 0;
}