BZOJ 2738. 矩阵乘法
整体二分加上一个二维树状数组数点即可。
#include <bits/stdc++.h> namespace IO { char buf[1 << 21], *p1 = buf, *p2 = buf; int p, p3 = -1; void read() {} inline int getc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++; } template <typename T, typename... T2> inline void read(T &x, T2 &... oth) { T f = 1; x = 0; char ch = getc(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getc(); } while (isdigit(ch)) { x = x * 10 + ch - 48; ch = getc(); } x *= f; read(oth...); } } const int N = 507; const int M = 500 * 500 + 6e4 + 7; int w[M], n, Q; struct Bit { int tree[N][N]; inline int lowbit(int x) { return x & -x; } inline void add(int x, int y, int v) { for (int i = x; i <= n; i += lowbit(i)) for (int j = y; j <= n; j += lowbit(j)) tree[i][j] += v; } inline int query(int x, int y) { int ans = 0; for (int i = x; i; i -= lowbit(i)) for (int j = y; j; j -= lowbit(j)) ans += tree[i][j]; return ans; } inline int query(int x1, int yy1, int x2, int y2) { return query(x2, y2) + query(x1 - 1, yy1 - 1) - query(x2, yy1 - 1) - query(x1 - 1, y2); } } bit; struct Node { int x1, yy1, x2, y2, k, id; } q[M], q1[M], q2[M]; int ans[M]; void solve(int l, int r, int L, int R) { if (l > r || L > R) return; if (l == r) { for (int i = L; i <= R; i++) if (q[i].id) ans[q[i].id] = w[l]; return; } int mid = l + r >> 1; int cnt1 = 0, cnt2 = 0; for (int i = L; i <= R; i++) { if (q[i].id) { int sum = bit.query(q[i].x1, q[i].yy1, q[i].x2, q[i].y2); if (q[i].k > sum) q[i].k -= sum, q2[++cnt2] = q[i]; else q1[++cnt1] = q[i]; } else { if (q[i].k <= w[mid]) bit.add(q[i].x1, q[i].yy1, 1), q1[++cnt1] = q[i]; else q2[++cnt2] = q[i]; } } for (int i = 1; i <= cnt1; i++) if (!q1[i].id) bit.add(q1[i].x1, q1[i].yy1, -1); for (int i = 1; i <= cnt1; i++) q[L + i - 1] = q1[i]; for (int i = 1; i <= cnt2; i++) q[L + cnt1 + i - 1] = q2[i]; solve(l, mid, L, L + cnt1 - 1); solve(mid + 1, r, L + cnt1, R); } int main() { IO::read(n, Q); int ccnt = 0, cnt = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { int x; IO::read(x); w[++ccnt] = x; ++cnt; q[cnt].x1 = i; q[cnt].yy1 = j; q[cnt].k = x; } for (int i = 1; i <= Q; i++) { ++cnt; IO::read(q[cnt].x1, q[cnt].yy1, q[cnt].x2, q[cnt].y2, q[cnt].k); q[cnt].id = i; } std::sort(w + 1, w + 1 + ccnt); ccnt = std::unique(w + 1, w + 1 + ccnt) - w - 1; solve(1, ccnt, 1, cnt); for (int i = 1; i <= Q; i++) printf("%d\n", ans[i]); return 0; }