[国家集训队]矩阵乘法

整体二分+二维数状数组。复杂度 \(\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\n", ans[i]);
	return 0;
}
posted @ 2021-01-26 15:43  AC-Evil  阅读(87)  评论(0编辑  收藏  举报