传送门
整体二分经典题。
直接整体二分第k大,用二维树状数组检验就行了。
代码:
#include<bits/stdc++.h>
#define N 505
#define Q 60005
using namespace std;
int n,m,a[N][N],val[N*N],bit[N][N],tot=0,ans[Q],cnt=0;
struct Query{int x1,y1,x2,y2,k,id;}q[Q],qtmp[Q];
struct Upd{int x,y,v;}upd[N*N];
inline int lowbit(int x){return x&-x;}
inline void update(int x,int y,int v){for(int i=x;i<=n;i+=lowbit(i))for(int j=y;j<=n;j+=lowbit(j))bit[i][j]+=v;}
inline int query(int x,int y){int ret=0;for(int i=x;i;i-=lowbit(i))for(int j=y;j;j-=lowbit(j))ret+=bit[i][j];return ret;}
inline void solve(int l,int r,int ql,int qr,int vl,int vr){
if(l>r)return;
if(ql==qr){
for(int i=l;i<=r;++i)ans[q[i].id]=val[ql];
return;
}
int mid=ql+qr>>1,hd=l-1,tl=r+1,vmid;
for(int i=vl;i<=vr;++i){
if(upd[i].v>mid)break;
vmid=i,update(upd[i].x,upd[i].y,1);
}
for(int i=l;i<=r;++i){
int tmp=query(q[i].x2,q[i].y2)+query(q[i].x1-1,q[i].y1-1)-query(q[i].x2,q[i].y1-1)-query(q[i].x1-1,q[i].y2);
if(tmp>=q[i].k)qtmp[++hd]=q[i];
else q[i].k-=tmp,qtmp[--tl]=q[i];
}
for(int i=vl;i<=vmid;++i)update(upd[i].x,upd[i].y,-1);
for(int i=l;i<=r;++i)q[i]=qtmp[i];
solve(l,hd,ql,mid,vl,vmid),solve(tl,r,mid+1,qr,vmid+1,vr);
}
inline bool cmp(Upd a,Upd b){return a.v<b.v;}
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)val[++tot]=a[i][j]=read();
sort(val+1,val+tot+1),tot=unique(val+1,val+tot+1)-val-1;
for(int i=1;i<=n;++i)for(int j=1;j<=n;++j){
a[i][j]=lower_bound(val+1,val+tot+1,a[i][j])-val;
upd[++cnt]=(Upd){i,j,a[i][j]};
}
for(int i=1;i<=m;++i){
int x1=read(),y1=read(),x2=read(),y2=read(),k=read();
q[i]=(Query){x1,y1,x2,y2,k,i};
}
sort(upd+1,upd+cnt+1,cmp);
solve(1,m,1,tot,1,cnt);
for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
return 0;
}