题目大意:
分析:
考虑一个合法的答案ddd,
一定满足区间内>=d区间内>=d区间内>=d的数的个数多于<d<d<d的个数,设差值为xxx,即 x>=0x>=0x>=0
找到最大ddd满足x>=0x>=0x>=0,dmaxd_{max}dmax即最大中位数
由于答案只可能是a1,a2..,ana1,a2..,ana1,a2..,an,
考虑离散后对于每个可能的答案建立一个主席树
假设bbb为aaa去重后的升序序列
以bib_ibi为中位数,将>=bi>=b_i>=bi的aaa记作+1,<bi<b_i<bi的记作-1,
那么对于[a,b],[c,d][a,b],[c,d][a,b],[c,d]是否合法,
就是xmax=[a,b]最大后缀和+[b+1,c−1]总和+[c,d]最大前缀和x_{max}=[a,b]最大后缀和+[b+1,c-1]总和+[c,d]最大前缀和xmax=[a,b]最大后缀和+[b+1,c−1]总和+[c,d]最大前缀和
是否满足xmax>=0x_{max}>=0xmax>=0,
可以用线段树维护中位数为bib_ibi时,序列的区间和,区间最大前缀和,区间最大后缀和
考虑
中位数bib_ibi ->bi+1b_{i+1}bi+1,
发现变化只有aaa中等于bib_ibi的数,由+1+1+1变成−1-1−1
直接用邻接表存起来这些位置,暴力改,然后以bib_ibi为历史版本线段树,
建立当前版本的线段树,将改过的点更新,因为当前版本线段树有多次加点加新链,所以注意点的重复的判断
以b1b_1b1为初始版本的线段树,
将b2,b3,b4,...,bnb_2,b_3,b_4,...,b_nb2,b3,b4,...,bn依次建成新的版本线段树即可
因为aaa中每个数最多被枚举1次,
所以时间是 O(nlog2n)O(nlog_2n)O(nlog2n)
对于一个询问,
二分bbb的下标,判断对应版本是否符合xmax>=0x_{max}>=0xmax>=0,判断直接找当前版本的树即可
时间是O(log22n)O(log_2^2n)O(log22n)
代码:
#include<bits/stdc++.h>
#define N 20005
using namespace std;
struct Node {
int ls, rs, sum, qian, hou;
}T[N*20];
int rot[N], nxt[N], pod[N];
int a[N], b[N], id[N], n, m, cnt;
int p[5];
void merge(int x) {
T[x].sum = T[T[x].ls].sum+T[T[x].rs].sum;
T[x].qian = max(T[T[x].ls].qian, T[T[x].ls].sum+T[T[x].rs].qian);
T[x].hou = max(T[T[x].rs].hou, T[T[x].rs].sum+T[T[x].ls].hou);
}
int Build(int L, int R) {
int now = ++cnt;
if (L == R) {
T[now].qian = T[now].hou = T[now].sum = 1;
return now;
}
int mid = (L+R)>>1;
if (L < R) {
T[now].ls = Build(L, mid);
T[now].rs = Build(mid+1, R);
}
merge(now);
return now;
}
void insert(int now2, int now1, int pos) {
int L = 1, R = n;
for (; T[now1].ls || T[now1].rs ;) {
int mid = (L+R)>>1;
if (pos <= mid) {
if (!T[now2].rs) T[now2].rs = T[now1].rs;
if (!T[now2].ls || T[now2].ls == T[now1].ls) T[now2].ls = ++cnt;
now1 = T[now1].ls;
now2 = T[now2].ls;
R = mid;
} else {
if (!T[now2].ls) T[now2].ls = T[now1].ls;
if (!T[now2].rs || T[now2].rs == T[now1].rs) T[now2].rs = ++cnt;
now1 = T[now1].rs;
now2 = T[now2].rs;
L = mid+1;
}
}
}
void update(int now, int L, int R, int pos) {
if (L == R) { T[now].sum = T[now].qian = T[now].hou = -1; return; }
int mid = (L+R)>>1;
if (pos <= mid) update(T[now].ls, L, mid, pos); else update(T[now].rs, mid+1, R, pos);
merge(now);
}
int Getmax(int now, int L, int R, int liml, int limr, int opt) {
if (L == liml && R == limr) {
if (opt == 1) return T[now].qian;
if (opt == 2) return T[now].hou;
if (opt == 3) return T[now].sum;
}
int mid = (L+R)>>1;
if (liml > mid) return Getmax(T[now].rs, mid+1, R, liml, limr, opt);
else if (limr <= mid) return Getmax(T[now].ls, L, mid, liml, limr, opt);
else {
if (opt == 1) return max(Getmax(T[now].ls, L, mid, liml, mid, 1),
Getmax(T[now].ls, L, mid, liml, mid, 3)+Getmax(T[now].rs, mid+1, R, mid+1, limr, 1));
if (opt == 2) return max(Getmax(T[now].rs, mid+1, R, mid+1, limr, 2),
Getmax(T[now].rs, mid+1, R, mid+1, limr, 3)+Getmax(T[now].ls, L, mid, liml, mid, 2));
if (opt == 3) return Getmax(T[now].ls, L, mid, liml, mid, 3)+Getmax(T[now].rs, mid+1, R, mid+1, limr, 3);
}
}
bool check(int now) {
now = rot[now];
int cmax1 = Getmax(now, 1, n, p[1], p[2], 2);
int cmax2 = Getmax(now, 1, n, p[3], p[4], 1);
int sum = 0;
if (p[2]+1 <= p[3]-1) sum = Getmax(now, 1, n, p[2]+1, p[3]-1, 3);
return (sum+cmax1+cmax2>=0);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];
sort(b+1, b+n+1);
m = unique(b+1, b+n+1)-b-1;
for (int i = 1; i <= n; i++) id[i] = lower_bound(b+1, b+m+1, a[i])-b;
for (int i = n; i >= 1; i--) nxt[i] = pod[id[i]], pod[id[i]] = i;
rot[1] = Build(1, n);
for (int i = 2; i <= m; i++) {
rot[i] = ++cnt;
for (int j = pod[i-1]; j; j = nxt[j]) insert(rot[i], rot[i-1], j);
for (int j = pod[i-1]; j; j = nxt[j]) update(rot[i], 1, n, j);
}
int asknum;
scanf("%d", &asknum);
int L, R, ans = 0;
for (int ask = 1; ask <= asknum; ask++) {
for (int i = 1; i <= 4; i++) scanf("%d", &p[i]), p[i] = (p[i]+ans)%n;
sort(p+1, p+4+1);
for (int i = 1; i <= 4; i++) ++p[i];
L = 1, R = m; ans = 0;
while (L <= R) {
int mid = (L+R)>>1;
if (check(mid)) ans = b[mid], L = mid+1; else R = mid-1;
}
printf("%d\n", ans);
}
return 0;
}