Middle
题目描述 :
一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。
位置也从0开始标号。
使用一些方式强制你在线。
输入格式 :
第一行序列长度n。
接下来n行按顺序给出a中的数。
接下来一行Q。
然后Q行每行a,b,c,d,我们令上个询问的答案是x(如果这是第一个询问则x=0)。
令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
将q从小到大排序之后,令真正的要询问的a=q[0],b=q[1],c=q[2],d=q[3]。
输出格式 :
Q行依次给出询问的答案。
Solution :
- 首先对于中位数,对于一个固定的区间,二分一个 x 将区间里大于等于 x 的数赋为 1,小于 x的数赋为 -1,若区间和大于等于 0 ,则该 x <= 最大的中位数
- 对于题目给出的区间,左右端点不固定,对于 b+1 到 c-1间的值是一定要算的,而 a 到 b 的可以记录一个最大的后缀,对 c 到 d 同理记录一个最大的前缀,然后判断这三者值的和是否 >=0 即可
所以可以用二分 + 主席树 然而我不会,或者分块做,对于每个块只需要记录块内存在的值对应的区间和、前缀、后缀最大值,然后对于不存在的值,用比它大的值暴力更新即可,因为该值在块内不存在,所以它的区间和、前缀后缀都与比它大的第一个存在的值相等。
Code :
#include<bits/stdc++.h>
using namespace std;
const int N = 2e4 + 7, B = 155, inf = 1e5;
int n, m, len, nn;
int l1, l2, r1, r2;
int a[N], h[N], blo[N];
int Lx[B][N], Rx[B][N], Sx[B][N];
template<class T> inline void read(T &x) {
bool f = false; x = 0;
char ch = getchar();
while (ch<'0' || ch>'9') {if (ch == '-') f = true; ch = getchar();}
while (ch>='0' && ch<='9') x = x * 10 + ch - '0', ch = getchar();
if (f) x = -x;
}
inline void Init() {
for (int i = 0; i <= B - 5; i++) {
for (int j = 0; j <= len + 5; j++) {
Lx[i][j] = Rx[i][j] = Sx[i][j] = -inf;
}
}
for (int blk = 1; blk <= (n - 1) / nn + 1; blk ++) {
int L = (blk - 1) * nn + 1, R = min(blk * nn, n);
for (int i = L; i <= R; i++) {
int nw = a[i], sum = 0;
for (int j = L; j <= R; j++) {
sum += a[j] >= nw ? 1 : -1;
}
Sx[blk][nw] = sum;
sum = 0;
for (int j = L; j <= R; j++) {
sum += a[j] >= nw ? 1 : -1;
Lx[blk][nw] = max(Lx[blk][nw], sum);
}
sum = 0;
for (int j = R; j >= L; j--) {
sum += a[j] >= nw ? 1 : -1;
Rx[blk][nw] = max(Rx[blk][nw], sum);
}
}
// Sx[blk][len + 1] = Lx[blk][len + 1] = Rx[blk][len + 1] = -inf;
for (int i = len; i >= 1; i--) {
Sx[blk][i] = max(Sx[blk][i], Sx[blk][i + 1]);
Lx[blk][i] = max(Lx[blk][i], Lx[blk][i + 1]);
Rx[blk][i] = max(Rx[blk][i], Rx[blk][i + 1]);
}
}
}
inline int getSum(int u, int v, int w) {
if (u > v) return 0;
int res = 0;
if (blo[u] == blo[v]) {
for (int i = u; i <= v; i++)
res += a[i] >= w ? 1 : -1;
return res;
}
for (int i = u; i <= nn * blo[u]; i++)
res += a[i] >= w ? 1 : -1;
for (int i = blo[u] + 1; i <= blo[v] - 1; i++)
res += Sx[i][w];
for (int i = nn * (blo[v] - 1) + 1; i <= v; i++)
res += a[i] >= w ? 1 : -1;
return res;
}
inline int getLx(int u, int v, int w) {
int mx = -inf, sum = 0;
if (blo[u] == blo[v]) {
for (int i = u; i <= v; i++) {
sum += a[i] >= w ? 1 : -1;
mx = max(mx, sum);
}
return mx;
}
for (int i = u; i <= nn * blo[u]; i++) {
sum += a[i] >= w ? 1 : -1;
mx = max(mx, sum);
}
for (int i = blo[u] + 1; i <= blo[v] - 1; i++) {
mx = max(mx, sum + Lx[i][w]);
sum += Sx[i][w];
}
for (int i = nn * (blo[v] - 1) + 1; i <= v; i++) {
sum += a[i] >= w ? 1 : -1;
mx = max(mx, sum);
}
return mx;
}
inline int getRx(int u, int v, int w) {
int mx = -inf, sum = 0;
if (blo[u] == blo[v]) {
for (int i = v; i >= u; i--) {
sum += a[i] >= w ? 1 : -1;
mx = max(mx, sum);
}
return mx;
}
for (int i = v; i >= nn * (blo[v] - 1) + 1; i--) {
sum += a[i] >= w ? 1 : -1;
mx = max(mx, sum);
}
for (int i = blo[v] - 1; i >= blo[u] + 1; i--) {
mx = max(mx, sum + Rx[i][w]);
sum += Sx[i][w];
}
for (int i = nn * blo[u]; i >= u; i--) {
sum += a[i] >= w ? 1 : -1;
mx = max(mx, sum);
}
return mx;
}
inline bool judge(int k) {
return getRx(l1, r1, k) + getSum(r1 + 1, l2 - 1, k) + getLx(l2, r2, k) >= 0;
}
int main() {
read(n);
nn = sqrt(n);
for (int i = 1; i <= n; i++) {
read(a[i]);
h[i] = a[i];
blo[i] = (i - 1) / nn + 1;
}
sort(h + 1, h + 1 + n);
len = unique(h + 1, h + 1 + n) - h - 1;
for (int i = 1; i <= n; i++) {
a[i] = lower_bound(h + 1, h + 1 + len, a[i]) - h;
}
Init(); read(m);
int prv = 0, q[5];
for (int i = 1; i <= m; i++) {
read(l1), read(r1), read(l2), read(r2);
q[1] = (l1 + prv) % n; q[2] = (r1 + prv) % n;
q[3] = (l2 + prv) % n; q[4] = (r2 + prv) % n;
sort(q + 1, q + 1 + 4);
l1 = q[1] + 1, r1 = q[2] + 1, l2 = q[3] + 1, r2 = q[4] + 1;
int l = 1, r = len, pos;
while (l <= r) {
int mid = (l + r) >> 1;
if (judge(mid)) pos = mid, l = mid + 1;
else r = mid - 1;
}
printf("%d\n", prv = h[pos]);
}
return 0;
}