P1527 [国家集训队] 矩阵乘法

发布时间 2023-12-13 16:58:49作者: cxqghzj

题意

给定一个矩阵,每次询问子矩阵的第 \(k\) 大。

Sol

考虑把莫队扔到二维上来做。

发现复杂度变为:\(O(n ^ 2 q ^ {\frac {3}{4}})\)

卡卡常就过了。

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <cmath>
#include <vector>
#include <cassert>
#define il inline
#define rg register
using namespace std;
#ifdef ONLINE_JUDGE

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;

#endif
int read() {
    int p = 0, flg = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') flg = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        p = p * 10 + c - '0';
        c = getchar();
    }
    return p * flg;
}
void write(int x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x > 9) {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}

const int N = 505, M = 2.5e5 + 5;
array <array <int, N>, N> mp;

namespace Cpt {

short bsi = 11;

array <short, M> agc;

class Node {

public:
    short l1, r1, l2, r2;
    int k, id;

    Node () : l1(), r1(), l2(), r2(), k(), id() {}

    Node (short _l1, short _l2, short _r1, short _r2, int _k, int _id) {
        l1 = _l1, r1 = _r1, l2 = _l2, r2 = _r2, k = _k, id = _id;
    }

    il bool operator <(const Node &t) const {
        if (agc[l1] != agc[t.l1]) return l1 < t.l1;
        if (agc[l2] != agc[t.l2]) return (agc[l1]) & 1 ? l2 < t.l2 : l2 > t.l2;
        if (agc[r2] != agc[t.r2]) return (agc[l2]) & 1 ? r2 < t.r2 : r2 > t.r2;
        else return (agc[r2]) & 1 ? r1 < t.r1 : r1 > t.r1;
        // if (l1 / bsi != t.l1 / bsi) return l1 < t.l1;
        // if (r1 / bsi != t.r1 / bsi) return (l1 / bsi) & 1 ? r1 < t.r1 : r1 > t.r1;
        // if (r2 / bsi != t.r2 / bsi) return (r1 / bsi) & 1 ? r2 < t.r2 : r2 > t.r2;
        // else return (r2 / bsi) & 1 ? l2 < t.l2 : l2 > t.l2;
    }

};

array <Node, M> edge;

namespace Blk {

short bsi = 610;

array <int, M> cur;
array <int, N> bk;

array <int, M> arc;

il int calc(int x) {
    return (x - 1) / bsi + 1;
}

il void modify(int x, short y) { cur[x] += y, bk[arc[x]] += y; }

il int query(int k) {
    rg short tot = 0;
    for (rg short i = 1; i <= 500; i++) {
        if (k - bk[i] <= 0) {
            tot = i;
            break;
        }
        k -= bk[i];
    }
    rg int ans = 0;
    for (rg int i = (tot - 1) * bsi + 1; i <= min(tot * bsi, (int)2.5e5); i++) {
        k -= (int)cur[i];
        if (k <= 0) {
            ans = i;
            break;
        }
    }
    // assert(ans >= 0);
    return ans;
}

}

il void modify(short x1, short x2, short y1, short y2, short k) {
    for (rg short i = x1; i <= x2; i++)
        for (rg short j = y1; j <= y2; j++)
            Blk::modify(mp[i][j], k);
}

}

vector <int> isl;
array <int, M> ans;

int main() {
    rg int n = read(), m = read();
    Cpt::bsi = n / pow(m, 0.25) / 3 + 1;
    Cpt::Blk::bsi = n + 1;
    for (short i = 1; i <= n; i++) Cpt::agc[i] = (i - 1) / Cpt::bsi + 1;
    for (int i = 1; i <= n * n; i++) Cpt::Blk::arc[i] = (i - 1) / Cpt::Blk::bsi + 1;
    for (rg short i = 1; i <= n; i++)
        for (rg short j = 1; j <= n; j++)
            mp[i][j] = read(), isl.push_back(mp[i][j]);
    sort(isl.begin(), isl.end());
    isl.erase(unique(isl.begin(), isl.end()), isl.end());
    for (rg short i = 1; i <= n; i++)
        for (rg short j = 1; j <= n; j++)
            mp[i][j] = lower_bound(isl.begin(), isl.end(), mp[i][j]) - isl.begin() + 1;
    // for (int i = 1; i <= n; i++) {
    //     for (int j = 1; j <= n; j++)
    //         write(mp[i][j]), putchar(32);
    //     puts("");
    // }
    for (rg int i = 1; i <= m; i++) {
        rg short x1 = read(), y1 = read(), x2 = read(), y2 = read();
        rg int k = read();
        Cpt::edge[i] = Cpt::Node(x1, y1, x2, y2, k, i);
    }
    sort(Cpt::edge.begin() + 1, Cpt::edge.begin() + 1 + m);
    rg short l1 = 1, l2 = 1, r1 = 1, r2 = 1; Cpt::Blk::cur[mp[1][1]]++, Cpt::Blk::bk[Cpt::Blk::calc(mp[1][1])]++;
    for (int i = 1; i <= m; i++) {
        rg short x1 = Cpt::edge[i].l1, x2 = Cpt::edge[i].l2,
                y1 = Cpt::edge[i].r1, y2 = Cpt::edge[i].r2;
        // write(x1), putchar(32);
        // write(y1), puts("@");
        while (l1 > x1) l1--, Cpt::modify(l1, l1, l2, r2, 1);
        while (l2 > x2) l2--, Cpt::modify(l1, r1, l2, l2, 1);
        while (r1 < y1) r1++, Cpt::modify(r1, r1, l2, r2, 1);
        while (r2 < y2) r2++, Cpt::modify(l1, r1, r2, r2, 1);
        while (l1 < x1) Cpt::modify(l1, l1, l2, r2, -1), l1++;
        while (l2 < x2) Cpt::modify(l1, r1, l2, l2, -1), l2++;
        while (r1 > y1) Cpt::modify(r1, r1, l2, r2, -1), r1--;
        while (r2 > y2) Cpt::modify(l1, r1, r2, r2, -1), r2--;
        ans[Cpt::edge[i].id] = Cpt::Blk::query(Cpt::edge[i].k);
    }
    for (rg int i = 1; i <= m; i++) {
        // assert(ans[i] > -2);
        write(isl[ans[i] - 1]), puts("");
    }
    return 0;
}