整体二分+二维数状数组。复杂度 (mathcal O((n^2+Q)log^3n))。
或者不使用二维数状数组,整体二分里面,采用扫描线将修改和询问一起做,这样复杂度可以消去一个 (log)。
#include <bits/stdc++.h>
using std::sort; using std::unique; using std::lower_bound; using std::vector;
const int N = 505, M = 60005;
int n, Q, a[N][N], b[N*N], tot = 0, ans[M];
struct node { int x, y; };
vector<node> st[N*N];
struct Query { int x1, y1, x2, y2, k, id; } q[M], stl[M], str[M];
#define lowbit(x) (x & (-x))
int C[N][N];
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))
C[i][j] += v;
}
int qry(int x, int y) {
int ans = 0;
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
ans += C[i][j];
return ans;
}
int query(int x1, int y1, int x2, int y2) {
return qry(x2, y2) - qry(x1-1, y2) - qry(x2, y1-1) + qry(x1-1, y1-1);
}
void solve(int l, int r, int x, int y) {
if (l > r) return;
if (x == y) {
for (int i = l; i <= r; i++) ans[q[i].id] = b[x];
return;
}
int mid = x+y>>1, totl = 0, totr = 0;
for (int i = x; i <= mid; i++)
for (int j = 0; j < st[i].size(); j++)
add(st[i][j].x, st[i][j].y, 1);
for (int i = l; i <= r; i++) {
int t = query(q[i].x1, q[i].y1, q[i].x2, q[i].y2);
if (t >= q[i].k) {
stl[totl++] = q[i];
} else {
q[i].k -= t;
str[totr++] = q[i];
}
}
for (int i = x; i <= mid; i++)
for (int j = 0; j < st[i].size(); j++)
add(st[i][j].x, st[i][j].y, -1);
for (int i = 0; i < totl; i++) q[l+i] = stl[i];
for (int i = 0; i < totr; i++) q[l+totl+i] = str[i];
solve(l, l+totl-1, x, mid), solve(l+totl, r, mid+1, y);
}
int main() {
scanf("%d%d", &n, &Q);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
scanf("%d", &a[i][j]), b[++tot] = a[i][j];
sort(b+1, b+tot+1); tot = unique(b+1, b+tot+1) - b - 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
st[lower_bound(b+1, b+tot+1, a[i][j]) - b].push_back((node){i, j});
for (int i = 1; i <= Q; i++)
scanf("%d%d%d%d%d", &q[i].x1, &q[i].y1, &q[i].x2, &q[i].y2, &q[i].k), q[i].id = i;
solve(1, Q, 1, tot);
for (int i = 1; i <= Q; i++) printf("%d
", ans[i]);
return 0;
}