简单的中位数

简单的中位数

给定一个 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\n",r);
        }
    }
    return 0;
}
posted @ 2020-12-16 17:57  肆之月  阅读(71)  评论(0编辑  收藏  举报