先吐槽一下这道题的题目———————-
这道题要求出所有询问的解并且所有问题的解都具有单调性,所以我们很容易能想出来这道题应该要整体二分,这道题的瓶颈是如何快速统计出来一个数到底在区间内排第几,其实看到矩形我们就应该想到树状数组,将所有大于当前二分答案的格子设为1,其余设为零,用树状数组求和,就可快速判断满不满足当前解为第K大,另外还可将所有点按照V值排序,这样每次二分出一个新的答案就可从之前的位置扫,还有当了l>r时一定要跳出,否则超时!!!
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;
#define maxn 521
struct ma
{
int x,y,val;
void read()
{
scanf("%d",&val);
}
bool operator <(ma b) const
{
return val<b.val;
}
}a[maxn*maxn];
struct my_query
{
int x1,y1,x2,y2,k,num;
void read()
{
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
}
}q[600001],nq[600001];
int c[maxn][maxn];
int n,m;
void add(int l,int r,int val)
{
for(int i=l;i<=n;i+=i&-i)
for(int j=r;j<=n;j+=j&-j)
c[i][j]+=val;
}
int query(int l,int r)
{
int re=0;
for(int i=l;i;i-=i&-i)
for(int j=r;j;j-=j&-j)
re+=c[i][j];
return re;
}
int ans[600001];
int now;
void fen(int x,int y,int l,int r)
{
int mid=x+y>>1;
if(x>y || l>r) return;
while(a[now+1].val<=mid && now!=n*n)
{
now++;
add(a[now].x,a[now].y,1);
}
while(a[now].val>mid && now)
{
add(a[now].x,a[now].y,-1);
now--;
}
int _l=l,_r=r;
for(int i=l;i<=r;i++)
{
int temp=query(q[i].x2,q[i].y2)+query(q[i].x1-1,q[i].y1-1)-query(q[i].x1-1,q[i].y2)-query(q[i].x2,q[i].y1-1);
if(q[i].k<=temp)
{
ans[q[i].num]=mid;
nq[_l++]=q[i];
}
else nq[_r--]=q[i];
}
memcpy(q+l,nq+l,sizeof(q[0])*(r-l+1));
fen(x,mid-1,l,_l-1);
fen(mid+1,y,_r+1,r);
}
int main()
{
scanf("%d%d",&n,&m);
int max_num=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
a[i*n-n+j].x=i;
a[i*n-n+j].y=j;
a[i*n-n+j].read();
if(a[i*n-n+j].val>max_num) max_num=a[i*n-n+j].val;
}
for(int i=1;i<=m;i++)
{
q[i].read();
q[i].num=i;
}
sort(a+1,a+1+n*n);
fen(0,max_num,1,m);
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}