「国家集训队」矩阵乘法

「国家集训队」矩阵乘法

传送门
还是静态区间第 \(k\) 小,只不过变成二维平面而不是序列了。
整体二分做法:就把树状数组改成二维的就好了。。。
还写主席树的话就不太好写了。。。
参考代码:

#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
template < class T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while ('0' > c || c > '9') f |= c == '-', c = getchar();
    while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
    s = f ? -s : s;
}

const int _ = 502, __ = 310002;

int n, q, res[__], tr[_][_];
int num; struct node { int x, y, v, id, a, b, c, d, k; } t[__], tt1[__], tt2[__];

inline void update(int x, int y, int v) {
    for (rg int i = x; i <= n; i += i & -i)
	    for (rg int j = y; j <= n; j += j & -j) tr[i][j] += v;
}

inline int query(int x, int y) {
    int res = 0;
    for (rg int i = x; i; i -= i & -i)
	    for (rg int j = y; j; j -= j & -j) res += tr[i][j];
    return res;
}

inline void solve(int ql, int qr, int l, int r) {
    if (ql > qr || l > r) return ;
    if (l == r) { for (rg int i = ql; i <= qr; ++i) if (t[i].id) res[t[i].id] = l; return ; }
    int mid = (l + r) >> 1; rg int p1 = 0, p2 = 0;
    for (rg int i = ql; i <= qr; ++i) {
    	if (t[i].id == 0) {
    	    if (t[i].v <= mid) update(t[i].x, t[i].y, 1), tt1[++p1] = t[i]; else tt2[++p2] = t[i];
    	} else {
    	    int cnt = query(t[i].c, t[i].d) - query(t[i].a - 1, t[i].d) - query(t[i].c, t[i].b - 1) + query(t[i].a - 1, t[i].b - 1);
    	    if (cnt >= t[i].k) tt1[++p1] = t[i]; else t[i].k -= cnt, tt2[++p2] = t[i];
    	}
    }
    for (rg int i = 1; i <= p1; ++i) if (tt1[i].id == 0) update(tt1[i].x, tt1[i].y, -1);
    for (rg int i = 1; i <= p1; ++i) t[ql + i - 1] = tt1[i];
    for (rg int i = 1; i <= p2; ++i) t[ql + p1 + i - 1] = tt2[i];
    solve(ql, ql + p1 - 1, l, mid), solve(ql + p1, qr, mid + 1, r);
}

int main() {
#ifndef ONLINE_JUDGE
    file("cpp");
#endif
    read(n), read(q);
    for (rg int i = 1; i <= n; ++i)
	for (rg int j = 1; j <= n; ++j) read(t[++num].v), t[num].x = i, t[num].y = j;
    for (rg int i = 1; i <= q; ++i) read(t[++num].a), read(t[num].b), read(t[num].c), read(t[num].d), read(t[num].k), t[num].id = i;
    solve(1, num, 0, 1000000000);
    for (rg int i = 1; i <= q; ++i) printf("%d\n", res[i]);
    return 0;
}
posted @ 2020-01-24 16:06  Sangber  阅读(179)  评论(0编辑  收藏  举报