洛谷1527 [国家集训队]矩阵乘法(整体二分)

题意:给你一个的矩阵,每次询问一个子矩形的第 k小数

输入格式:第一行有两个整数,分别表示矩阵大小 n和询问组数 q

第 2到第 (n + 1)行,每行 n个整数,表示这个矩阵。第 (i + 1)行的第 j个数表示矩阵第 i行第 j列的数ai,j

接下来 q行,每行五个整数x1,y1,x2,y2,k,表示一组询问,要求找到以(x1,y1)为左上角,(x2,y2)为右下角的子矩形中的第 k小数

输出格式:对于每组询问,输出一行一个整数表示答案。

#include<cstdio>
#include<algorithm>
const int N = 505;
const int M = 6e4 + 5;

struct Matrix{
    int x, y, val;
    bool operator <(const Matrix &u)const{
        return val < u.val;
    }
}matrix[N * N];

struct Query{
    int x1, y1, x2, y2, k;
}q[M];

struct BIT{
    int n, m;
    int c[N][N];

    inline void init(int x, int y) { n = x, m = y; }
    inline int lowbit(int &x) { return x & -x; }

    void modify(int x, int y, int p){
        for(int i = x; i <= n; i += lowbit(i))
            for(int t = y; t <= m; t += lowbit(t)){
                c[i][t] += p;
            }
    }

    int query(int x,int y){
        int ans = 0;
        for(int i = x; i; i -= lowbit(i))
            for(int t = y; t; t -= lowbit(t)){
                ans += c[i][t];
            }
        return ans;
    }

    int Query(Query p){
        return query(p.x2, p.y2) + query(p.x1 - 1, p.y1 - 1) - query(p.x1 - 1, p.y2) - query(p.x2, p.y1 - 1);
    }
}Tree;

int n, m, tot;
int ans[M], id[M], cur[M], t1[M], t2[M];

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[id[i]] = matrix[l].val;
        return ;    // 找到解
    }
    int mid = (l + r) >> 1;
    for(int i = l; i <= mid; ++i)  Tree.modify(matrix[i].x, matrix[i].y, 1);
    int cl = 0, cr = 0;
    for(int i = ql; i <= qr; ++i){
        int u = id[i];    // 当前要处理的询问
        int s = cur[u] + Tree.Query(q[u]);    // 加上当前区间中位于q[u]询问矩阵范围内的点
        if(s >= q[u].k)  t1[++cl] = u;
        else  t2[++cr] = u, cur[u] = s;
    }
    int kk = ql - 1;
    for(int i = 1; i <= cl; ++i)  id[++kk] = t1[i];     // 左右分组
    for(int i = 1; i <= cr; ++i)  id[++kk] = t2[i];
    for(int i = l; i <= mid; ++i)  Tree.modify(matrix[i].x, matrix[i].y, -1);
    solve(l, mid, ql, ql + cl - 1);
    solve(mid + 1, r, ql + cl, qr);
}

int main(){
    scanf("%d%d", &n, &m);
    Tree.init(n, n);
    for(int i = 1, val; i <= n; ++i)
        for(int t = 1; t <= n; ++t){
            scanf("%d", &val);
            matrix[++tot] = Matrix{i, t, val};
        }
    std::sort(matrix + 1, matrix + 1 + tot);
    for(int i = 1; i <= m; ++i)  id[i] = i;
    for(int i = 1; i <= m; ++i)
        scanf("%d%d%d%d%d", &q[i].x1, &q[i].y1, &q[i].x2, &q[i].y2, &q[i].k);
    solve(1, tot, 1, m);
    for(int i = 1; i <= m; ++i)  printf("%d
", ans[i]);
    return 0;
}
你只有十分努力,才能看上去毫不费力。
原文地址:https://www.cnblogs.com/214txdy/p/14024389.html