【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=2653
【题解】
遇到求中位数的题,不难想到二分答案,然后把序列转化为-1和1。
考虑二分后如何判断,对于每个不同的二分的值,可以按位置为下标建立一棵线段树,每个节点记录当前是-1还是1。 [b,c] [ b , c ] 必须全取。 [a,b) [ a , b ) , (c,d] ( c , d ] 是最大右(左)子段和。然后把所得的值与0进行比较, <0 < 0 则不合法。
由于对于两个相邻的二分的值,线段树的叶子节点上只有一个点的值会改变。所以可以用可持久化线段树实现。
时间复杂度: O(N∗log2N) O ( N ∗ l o g 2 N )
【代码】
/* - - - - - - - - - - - - - - -
User : VanishD
problem : [bzoj2653]
Points : segment tree
- - - - - - - - - - - - - - - */
# include
# define ll long long
# define inf 0x3f3f3f3f
# define N 100010
using namespace std;
int read(){
int tmp = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
return tmp * fh;
}
struct Node{
int num, id;
}h[N];
struct Tree{
int pl, pr, num, numl, numr;
}T[N * 20];
int p[10], n, q, number[N], L, R, rt[N], place, now, a, b, c, d;
map <int, int> mp;
vector <int> in[N];
void build(int &p, int l, int r){
p = ++place;
T[p].numl = 0, T[p].numr = 0;
T[p].num = -(r - l + 1);
if (l != r){
int mid = (l + r) / 2;
build(T[p].pl, l, mid);
build(T[p].pr, mid + 1, r);
}
}
void reget(int p){
T[p].numl = max(T[T[p].pl].num + T[T[p].pr].numl, T[T[p].pl].numl);
T[p].numr = max(T[T[p].pr].num + T[T[p].pl].numr, T[T[p].pr].numr);
T[p].num = T[T[p].pl].num + T[T[p].pr].num;
}
void extend(int &p, int las, int num, int l, int r){
p = ++place;
if (l == r){
T[p].num = T[las].num + 2;
T[p].numl = T[p].numr = 1;
}
else {
int mid = (l + r) / 2;
if (num <= mid){
extend(T[p].pl, T[las].pl, num, l, mid);
T[p].pr = T[las].pr;
}
else {
extend(T[p].pr, T[las].pr, num, mid + 1, r);
T[p].pl = T[las].pl;
}
reget(p);
}
}
int query(int p, int ql, int qr, int l, int r){
if (ql == l && qr == r) return T[p].num;
int mid = (l + r) / 2;
if (mid >= qr) return query(T[p].pl, ql, qr, l, mid);
else if (mid < ql) return query(T[p].pr, ql, qr, mid + 1, r);
else return query(T[p].pl, ql, mid, l, mid) + query(T[p].pr, mid + 1, qr, mid + 1, r);
}
int queryl(int p, int ql, int qr, int l, int r, int ths){
if (ql == l && qr == r){
now = max(now, T[p].numl + ths);
return T[p].num;
}
int mid = (l + r) / 2;
if (mid >= qr) return queryl(T[p].pl, ql, qr, l, mid, ths);
else if (mid < ql) return queryl(T[p].pr, ql, qr, mid + 1, r, ths);
else {
int num = queryl(T[p].pl, ql, mid, l, mid, ths);
num += queryl(T[p].pr, mid + 1, qr, mid + 1, r, num + ths);
return num;
}
}
int queryr(int p, int ql, int qr, int l, int r, int ths){
if (ql == l && qr == r){
now = max(now, T[p].numr + ths);
return T[p].num;
}
int mid = (l + r) / 2;
if (mid >= qr) return queryr(T[p].pl, ql, qr, l, mid, ths);
else if (mid < ql) return queryr(T[p].pr, ql, qr, mid + 1, r, ths);
else {
int num = queryr(T[p].pr, mid + 1, qr, mid + 1, r, ths);
num += queryr(T[p].pl, ql, mid, l, mid, num + ths);
return num;
}
}
bool check(int x){
int num = query(rt[x], b, c, 1, n); now = -inf;
queryr(rt[x], a, b - 1, 1, n, 0);
num += now; now = - inf;
queryl(rt[x], c + 1, d, 1, n, 0);
num += now;
return num >= 0;
}
bool cmp(Node x, Node y){
return x.num < y.num;
}
int main(){
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
n = read();
for (int i = 1; i <= n; i++)
h[i].num = read(), h[i].id = i;
sort(h + 1, h + n + 1, cmp);
L = 1, R = 0;
for (int i = 1; i <= n; i++){
if (mp.find(h[i].num) == mp.end())
mp[h[i].num] = ++R, number[R] = h[i].num;
in[R].push_back(h[i].id);
}
build(rt[R + 1], 1, n);
for (int i = R; i >= 1; i--){
rt[i] = rt[i + 1];
for (unsigned j = 0; j < in[i].size(); j++)
extend(rt[i], rt[i], in[i][j], 1, n);
}
q = read();
int lastans = 0;
for (int i = 1; i <= q; i++){
p[1] = (read() + lastans) % n + 1, p[2] = (read() + lastans) % n + 1;
p[3] = (read() + lastans) % n + 1, p[4] = (read() + lastans) % n + 1;
sort(p + 1, p + 4 + 1);
a = p[1], b = p[2], c = p[3], d = p[4];
int pl = L, pr = R;
while (pl <= pr){
int mid = (pl + pr) / 2;
if (check(mid))
pl = mid + 1, lastans = mid;
else pr = mid - 1;
}
lastans = number[lastans];
printf("%d\n", lastans);
}
return 0;
}