简单的中位数
给定一个 n×m 的矩阵,以及 q 次询问,每次询问包括 4 个值分别为 a,b,c,d 代表着左上角为(a,b)右下角为(c,d)的子矩阵,求在这个子矩阵中的中位数是多少,若矩阵中的个数为偶数个,则取中间偏小的数。如矩阵中的数为 1,2,3,4,那么答案是 2
输入格式
一行一个整数 TT(1< T< 100)代表 TT 组数据
第二行三个整数 n,m,q(1≤n,m≤100,1≤q≤100000)代表矩阵的行列以及询问次数。其中对于所有数据 n×m 的总和不超过 3e5,qq 的总和不超过 1e6
接下来 n 行 m 个数 Aij 代表初始矩阵中的元素(1≤Aij≤500)
最后 q 行,每行 4 个整数 a,b,c,d,(1≤a≤c≤n,1≤b≤d≤m)
输出格式
每组数据输出 q 行每行一个答案
输出时每行末尾的多余空格,不影响答案正确性
样例输入
1
5 5 2
5 4 3 2 1
10 11 12 13 25
9 8 7 6 14
15 16 17 18 19
24 23 22 21 20
5 1 5 5
2 1 5 5
样例输出
22
15
二分
ch[v][i][j],ij子矩阵中值小于等于v的个数
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f,mod=1e9+7,MAXN=102;
#define lowbit(x) ((x)&(-x))
#define Init(arr,val) memset(arr,val,sizeof(arr))
typedef long long ll;
int a[MAXN][MAXN],ch[501][MAXN][MAXN],n,m,q;
bool vis[501];
void get(int k){//k的求前缀和
vis[k]=1;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(a[i][j]<=k)ch[k][i][j]=-1;
else ch[k][i][j]=1;
ch[k][i][j]+=ch[k][i-1][j]+ch[k][i][j-1]-ch[k][i-1][j-1];
}
}
}
int x,y,xx,yy;
int check(int ans){
if(!vis[ans])get(ans);
return ch[ans][xx][yy]-ch[ans][xx][y-1]-ch[ans][x-1][yy]+ch[ans][x-1][y-1];
}
int main() {
int t=0;
scanf("%d",&t);
while(t--){
Init(vis,0);
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&a[i][j]);
while(q--){
scanf("%d%d%d%d",&x,&y,&xx,&yy);
int l=1,r=500,num=(xx-x+1)*(yy-y+1);
if(num&1){
while(l<r){
int mid=(l+r)>>1;
if(check(mid)>-1)l=mid+1;
else r=mid;
}
}else{
while(l<r){
int mid=(l+r)>>1;
if(check(mid)>0)l=mid+1;
else r=mid;
}
}
printf("%d
",r);
}
}
return 0;
}