题意
求矩阵区间第k小。
思路
将所有询问整体二分,用树状数组维护求答案。
日常挖坑->blog
代码
#include <cstdio>
#include <algorithm>
struct node {
int x1, y1, x2, y2, k, pos;
} a[360001], a1[360001], a2[360001];
int n, q, cnt;
int ans[60001], t[501][501];
inline int lowbit(int x) {
return x & -x;
}
void add(int x, int y, int val) {
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= n; j += lowbit(j))
t[i][j] += val;
}
int ask(int x, int y) {
int res = 0;
for (int i = x; i >= 1; i -= lowbit(i))
for (int j = y; j >= 1; j -= lowbit(j))
res += t[i][j];
return res;
}
int query(int x1, int y1, int x2, int y2) {
return ask(x2, y2) - ask(x1 - 1, y2) - ask(x2, y1 - 1) + ask(x1 - 1, y1 - 1);
}
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 (a[i].pos) ans[a[i].pos] = l;
return;
}
int mid = l + r >> 1, cnt1 = 0, cnt2 = 0;
for (int i = L; i <= R; i++)
if (a[i].pos) {
int tmp = query(a[i].x1, a[i].y1, a[i].x2, a[i].y2);
if (tmp >= a[i].k) a1[++cnt1] = a[i];
else a[i].k -= tmp, a2[++cnt2] = a[i];
} else {
if (a[i].k <= mid) add(a[i].x1, a[i].y1, 1), a1[++cnt1] = a[i];
else a2[++cnt2] = a[i];
}
for (int i = 1; i <= cnt1; i++)
if (!a1[i].pos) add(a1[i].x1, a1[i].y1, -1);
for (int i = 1; i <= cnt1; i++)
a[L + i - 1] = a1[i];
for (int i = 1; i <= cnt2; i++)
a[L + cnt1 + i - 1] = a2[i];
solve(l, mid, L, L + cnt1 - 1);
solve(mid + 1, r, L + cnt1, R);
}
int main() {
scanf("%d %d", &n, &q);
int mx = 0, x;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
scanf("%d", &x);
a[++cnt] = (node){i, j, 0, 0, x, 0};
mx = std::max(mx, x);
}
for (int i = 1; i <= q; i++) {
int x1, y1, x2, y2, k;
scanf("%d %d %d %d %d", &x1, &y1, &x2, &y2, &k);
a[++cnt] = (node){x1, y1, x2, y2, k, i};
}
solve(0, mx + 1, 1, cnt);
for (int i = 1; i <= q; i++)
printf("%d\n", ans[i]);
}