luogu P1527 [国家集训队]矩阵乘法
https://www.luogu.com.cn/problem/P1527
整体二分板子题
二分一个mid,把<=mid的全部设为1
用二维树状数组维护前缀个数和
然后套板子即可
code:
#include<bits/stdc++.h>
#define N 606
#define lowbit(x) (x & -x)
using namespace std;
int ans[N * N], id[N * N], n, Q, A[N * N], B[N * N], cnt;
struct QQ {
int x, y, xx, yy, k;
} q[N * N];
int t[N][N];
void add(int x, int y, int o) {
for(int i = x; i <= n; i += lowbit(i))
for(int j = y; j <= n; j += lowbit(j))
t[i][j] += o;
}
int query(int x, int y) {
int ret = 0;
for(int i = x; i; i -= lowbit(i))
for(int j = y; j; j -= lowbit(j))
ret += t[i][j];
return ret;
}
int calc(int x, int y, int xx, int yy) {
return query(xx, yy) - query(x - 1, yy) - query(xx, y - 1) + query(x - 1, y - 1);
}
struct AA {
int x, y, val;
} a[N * N];
int cmp(AA x, AA y) {
return x.val < y.val;
}
void solve(int l, int r, int L, int R) { //printf(" %d %d %d %d\n", l, r, L, R);
if(L > R) return ;
if(l == r) {
for(int i = L; i <= R; i ++) ans[id[i]] = a[l].val;
// printf("*%d*", l);
return ;
}
int mid = (l + r) >> 1;
for(int i = l; i <= mid; i ++) add(a[i].x, a[i].y, 1);
int sz1 = 0, sz2 = 0;
for(int i = L; i <= R; i ++) {
int j = id[i], s = calc(q[j].x, q[j].y, q[j].xx, q[j].yy);
if(s >= q[j].k) A[++ sz1] = j;
else B[++ sz2] = j, q[j].k -= s;
}
for(int i = 1; i <= sz1; i ++) id[L + i - 1] = A[i];
for(int i = 1; i <= sz2; i ++) id[L + sz1 - 1 + i] = B[i];
for(int i = l; i <= mid; i ++) add(a[i].x, a[i].y, - 1);
solve(l, mid, L, L + sz1 - 1), solve(mid + 1, r, L + sz1, R);
}
int main() {
scanf("%d%d", &n, &Q);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++) {
scanf("%d", &a[++ cnt].val);
a[cnt].x = i, a[cnt].y = j;
}
sort(a + 1, a + 1 + cnt, cmp);
for(int i = 1; i <= Q; i ++) scanf("%d%d%d%d%d", &q[i].x, &q[i].y, &q[i].xx, &q[i].yy, &q[i].k);
for(int i = 1; i <= Q; i ++) id[i] = i;
solve(1, cnt, 1, Q);
for(int i = 1; i <= Q; i ++) printf("%d\n", ans[i]);
return 0;
}