版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 https://blog.csdn.net/A_Bright_CH/article/details/83443334
题目
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。
题解
整体二分+树状数组
求第k小的数我怎么就没想到整体二分呢!
还是挺裸的,把所有元素记录下位置一并放入中b队列中,询问也是。
因为是二维的,所以树状数组也要升级成二维的,s[x][y]表示(1,1)-(x,y)这个矩阵中小于等于mid的数的个数,酱紫就可以判断一个询问要取到bl还是br了。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=510,MAXQ=60010;
inline int read()
{
int re=0;char ch=getchar();
while(ch<'0' || ch>'9') ch=getchar();
while(ch>='0' && ch<='9') re=re*10+(ch^48),ch=getchar();
return re;
}
int n,Q;
struct U{int x,y,c;}a[MAXN*MAXN];int len=0;
bool cmp(U u1,U u2){return u1.c<u2.c;}
struct O{int x1,y1,x2,y2,k,id;}b[MAXQ];
int s[MAXN][MAXN];
void add(int x,int y,int c)
{
for(int i=x;i<=n;i+=i&-i)
for(int j=y;j<=n;j+=j&-j) s[i][j]+=c;
}
int getsum(int x,int y)
{
int re=0;
for(int i=x;i>=1;i-=i&-i)
for(int j=y;j>=1;j-=j&-j) re+=s[i][j];
return re;
}
void change(int x,int y,int c)
{
add(x,y,c);//一个改点求段的二维树状数组
/*if(x-1 && y-1) add(x-1,y-1,c);
if(x-1) add(x-1,y,-c);
if(y-1) add(x,y-1,-c);*/
}
int query(int x1,int y1,int x2,int y2)
{
return getsum(x2,y2)+getsum(x1-1,y1-1)-getsum(x1-1,y2)-getsum(x2,y1-1);
}
int ans[MAXQ];
O bl[MAXQ],br[MAXQ];
void solve(int l,int r,int ql,int qr)
{
if(ql>qr) return ;
if(l==r)
{
for(int i=ql;i<=qr;i++) ans[b[i].id]=a[l].c;
return ;
}
int tl=0,tr=0;
int mid=l+r>>1;
for(int i=l;i<=mid;i++) change(a[i].x,a[i].y,1);
for(int i=ql;i<=qr;i++)
{
int tk=query(b[i].x1,b[i].y1,b[i].x2,b[i].y2);
if(b[i].k<=tk) bl[++tl]=b[i];
else br[++tr]=b[i],br[tr].k-=tk;
}
for(int i=ql,j=1;j<=tl;i++,j++) b[i]=bl[j];
for(int i=qr,j=tr;j>=1;i--,j--) b[i]=br[j];
for(int i=l;i<=mid;i++) change(a[i].x,a[i].y,-1);//debug (;i<=r;)
solve(l,mid,ql,ql+tl-1);solve(mid+1,r,ql+tl,qr);
}
int main()
{
n=read();Q=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) a[++len]=(U){i,j,read()};
sort(a+1,a+len+1,cmp);
for(int i=1;i<=Q;i++) b[i].x1=read(),b[i].y1=read(),b[i].x2=read(),b[i].y2=read(),b[i].k=read(),b[i].id=i;
solve(1,len,1,Q);
for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
return 0;
}