#4604. The kth maximum number
给定一个大小不超过5×1055 \times 10 ^ 55×105的矩形区域,有一些点有点权。
每次询问给定x1,y1,x2,y2,kx_1, y_1, x_2, y_2, kx1,y1,x2,y2,k问以x1,y1x_1, y_1x1,y1为右下角,x2,y2x_2, y_2x2,y2为左上角的矩形中权值第kkk大是多少。
其实于P1527 [国家集训队]矩阵乘法是基本差不多的,就是矩形的大小变大了,无法进行二维树状数组操作
但是,矩形数点不就是一个二维偏序问题嘛,可以树套树来解决,于是我们有了如下的做法,
考虑整体二分,
先对x,yx, yx,y进行离散化(保证常数小一点吧),对每个横左边建立一颗主席树,同时用树状数组维护,
于是在二分过程中,我们对每个点的修改操作,直接修改即可,同时对主席树加上内存回收机制,这样可以保证不会炸空间,
之后对每个矩阵的查询,我们只要在区间[x1,x2][x_1, x_2][x1,x2]的主席树上查询值在[y1,y2][y_1, y_2][y1,y2]有多少即可,
整体复杂度O(nlog3n)O(n \log ^ 3 n)O(nlog3n),由于nnn比较小,实测跑得还是挺快的。
#include <bits/stdc++.h>using namespace std;const int N = 1e5 + 10;int X[N], Y[N], V[N], ans[N], n, m, nn, mm, tot;int root[N], ls[N * 300], rs[N * 300], sum[N * 300], stk[N * 300], top, num;void update(int &rt, int l, int r, int x, int v) {if (!rt) {if (top) {rt = stk[top--];}else {rt = ++num;}}sum[rt] += v;if (l == r) {return ;}int mid = l + r >> 1;if (x <= mid) {update(ls[rt], l, mid, x, v);}else {update(rs[rt], mid + 1, r, x, v);}
}int A[50], B[50], cnt1, cnt2;int query(int l, int r, int L, int R) {if (l >= L && r <= R) {int res = 0;for (int i = 1; i <= cnt1; i++) {res -= sum[A[i]];}for (int i =1 ; i <= cnt2; i++) {res += sum[B[i]];}return res;}int mid = l + r >> 1, res = 0, A1[50], B1[50];if (L <= mid) {for (int i = 1; i <= cnt1; i++) {A1[i] = A[i];A[i] = ls[A[i]];}for (int i = 1; i <= cnt2; i++) {B1[i] = B[i];B[i] = ls[B[i]];}res += query(l, mid, L, R);for (int i = 1; i <= cnt1; i++) {A[i] = A1[i];}for (int i = 1; i <= cnt2; i++) {B[i] = B1[i];}}if (R > mid) {for (int i = 1; i <= cnt1; i++) {A1[i] = A[i];A[i] = rs[A[i]];}for (int i = 1; i <= cnt2; i++) {B1[i] = B[i];B[i] = rs[B[i]];}res += query(mid + 1, r, L, R);for (int i = 1; i <= cnt1; i++) {A[i] = A1[i];}for (int i = 1; i <= cnt2; i++) {B[i] = B1[i];}}return res;
}inline int lowbit(int x) {return x & (-x);
}void update(int x, int y, int v) {while (x <= nn) {update(root[x], 1, mm, y, v);x += lowbit(x);}
}int get_sum(int l, int r, int L, int R) {if (l > r || L > R) {return 0;}cnt1 = cnt2 = 0;for (int i = l - 1; i; i -= lowbit(i)) {A[++cnt1] = root[i];}for (int i = r; i; i -= lowbit(i)) {B[++cnt2] = root[i];}return query(1, mm, L, R);
}struct Res {int x1, y1, x2, y2, v, id, op;
}q[N], q1[N], q2[N];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].op == 2) {ans[q[i].id] = l;}}return ;}int mid = l + r >> 1, cnt1 = 0, cnt2 = 0;for (int i = L; i <= R; i++) {if (q[i].op == 1) {if (q[i].v > V[mid]) {update(q[i].x1, q[i].y1, 1);q2[++cnt2] = q[i];}else {q1[++cnt1] = q[i];}}else {int cur = get_sum(q[i].x1, q[i].x2, q[i].y1, q[i].y2);if (cur >= q[i].v) {q2[++cnt2] = q[i];}else {q[i].v -= cur;q1[++cnt1] = q[i];}}}for (int i = 1; i <= cnt2; i++) {if (q2[i].op == 1) {update(q2[i].x1, q2[i].y1, -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() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);scanf("%d %d", &n, &m);for (int i = 1, op; i <= m; i++) {scanf("%d", &op);if (op & 1) {int x, y, v;scanf("%d %d %d", &x, &y, &v);q[i] = {x, y, 0, 0, v, 0, 1};X[++tot] = x, Y[tot] = y, V[tot] = v;}else {int x1, y1, x2, y2, v;scanf("%d %d %d %d %d", &x1, &y1, &x2, &y2, &v);q[i] = {x1, y1, x2, y2, v, i, 2};}}sort(X + 1, X + 1 + tot), sort(Y + 1, Y + 1 + tot), sort(V + 1, V + 1 + tot);nn = unique(X + 1, X + 1 + tot) - (X + 1);mm = unique(Y + 1, Y + 1 + tot) - (Y + 1);tot = unique(V + 1, V + 1 + tot) - (V + 1);for (int i = 1; i <= m; i++) {if (q[i].op & 1) {q[i].x1 = lower_bound(X + 1, X + 1 + nn, q[i].x1) - X;q[i].y1 = lower_bound(Y + 1, Y + 1 + mm, q[i].y1) - Y;}else {q[i].x1 = lower_bound(X + 1, X + 1 + nn, q[i].x1) - X;q[i].y1 = lower_bound(Y + 1, Y + 1 + mm, q[i].y1) - Y;q[i].x2 = upper_bound(X + 1, X + 1 + nn, q[i].x2) - X;q[i].y2 = upper_bound(Y + 1, Y + 1 + mm, q[i].y2) - Y;q[i].x2--, q[i].y2--;}}for (int i = 1; i <= m; i++) {ans[i] = -1;}solve(0, tot, 1, m);for (int i = 1; i <= m; i++) {if (ans[i] != -1) {if (ans[i] == 0) {puts("NAIVE!ORZzyz.");}else {printf("%d\n", V[ans[i]]);}}}return 0;
}