1. 程式人生 > >【LG1527】[國家集訓隊]矩陣乘法

【LG1527】[國家集訓隊]矩陣乘法

【LG1527】[國家集訓隊]矩陣乘法

題面

洛谷

題解

我也不知道為什麼取個這樣的名字。。。
其實就是區間\(kth\)擴充套件到二維
還是用整體二分搞啦,把樹狀陣列換成二維的
其他的基本沒有什麼差別
複雜度\(nlog^3\)
程式碼

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector> 
using namespace std;
namespace IO { 
    const int BUFSIZE = 1 << 20; 
    char ibuf[BUFSIZE], *is = ibuf, *it = ibuf; 
    inline char gc() { 
        if (is == it) it = (is = ibuf) + fread(ibuf, 1, BUFSIZE, stdin); 
        return *is++; 
    } 
} 
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (ch != '-' && (ch > '9' || ch < '0')) ch = IO::gc();
    if (ch == '-') w = -1 , ch = IO::gc();
    while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = IO::gc();
    return w * data;
} 
const int SIZE = 400005, MAX_N = 505; 
struct Query { int op, x, y, _x, _y, k; } q[SIZE], rq[SIZE], lq[SIZE]; 
void Output(int x) { 
    printf("%d %d %d %d %d %d\n", q[x].op, q[x].x, q[x].y, q[x]._x, q[x]._y, q[x].k); 
} 
int N, M, ans[SIZE]; 
int c[MAX_N][MAX_N]; 
inline int lb(int x) { return x & -x; } 
void add(int x, int y, int v) { 
    for (int i = x; i <= N; i += lb(i)) 
        for (int j = y; j <= N; j += lb(j)) 
            c[i][j] += v; 
} 
int sum(int x, int y) { 
    int res = 0; 
    for (int i = x; i > 0; i -= lb(i)) 
        for (int j = y; j > 0; j -= lb(j)) 
            res += c[i][j]; 
    return res; 
} 
void Div (int lval, int rval, int st, int ed) { 
    if (st > ed) return ; 
    if (lval == rval) { 
        for (int i = st; i <= ed; i++) if (q[i].op != 0) ans[q[i].op] = lval; 
        return ; 
    } 
    int mid = (lval + rval) >> 1; 
    int lt = 0, rt = 0; 
    for (int i = st; i <= ed; i++) { 
        int x = q[i].x, y = q[i].y; 
        if (q[i].op == 0) { 
            if (q[i].k <= mid) lq[++lt] = q[i], add(x, y, 1); 
            else rq[++rt] = q[i]; 
        } else { 
            int _x = q[i]._x, _y = q[i]._y; 
            int res = sum(_x, _y) - sum(x - 1, _y) - sum(_x, y - 1) + sum(x - 1, y - 1); 
            if (q[i].k <= res) lq[++lt] = q[i]; 
            else q[i].k -= res, rq[++rt] = q[i]; 
        } 
    } 
    for (int i = st; i <= ed; i++) if (q[i].op == 0 && q[i].k <= mid) add(q[i].x, q[i].y, -1); 
    for (int i = 1; i <= lt; i++) q[st + i - 1] = lq[i]; 
    for (int i = 1; i <= rt; i++) q[st + lt + i - 1] = rq[i]; 
    Div(lval, mid, st, st + lt - 1); 
    Div(mid + 1, rval, st + lt, ed); 
} 
int main () {  
    N = gi(), M = gi(); 
    int cnt = 0; 
    for (int i = 1; i <= N; i++) 
        for (int j = 1; j <= N; j++) 
            q[++cnt] = (Query){0, i, j, 0, 0, gi()}; 
    for (int i = 1; i <= M; i++) q[++cnt] = (Query){i, gi(), gi(), gi(), gi(), gi()}; 
    Div(1, 1e9, 1, cnt); 
    for (int i = 1; i <= M; i++) printf("%d\n", ans[i]); 
    return 0; 
}