题目链接:洛谷
题目大意:给定一个长度为$n$的序列,每次询问左端点在$[a,b]$,右端点在$[c,d]$的所有子区间的中位数的最大值。(强制在线)
这里的中位数定义为,对于一个长度为$n$的序列排序之后为$a_0,a_1,ldots,a_{n-1}$,则$a_{lfloorfrac{n}{2} floor}$为这个序列的中位数。
数据范围:$1leq nleq 20000$,$1leq qleq 25000$,$1leq aleq bleq cleq dleq n$
这道题才是真正的主席树!
首先我们考虑离散化,然后二分答案,判断这些区间的中位数是否有可能$geq mid$,那怎么判断呢?
我们发现,如果把这个序列的所有$geq mid$的数改为1,$<mid$的数改为$-1$,则上述条件等价于这个新的数列之和非负。(这是一个非常神仙的套路)
所以我们对于所有的数$a_i$,预处理出这个1/-1的序列,但是这样空间会爆炸。
我们发现这些序列中,$a_{i-1}$和$a_i$的序列之间仅有一位不同。
于是主席树闪亮登场。
然后判断一下左端点在$[a,b]$,右端点在$[c,d]$的最大子段和,判断一下是否$geq 0$。

1 #include<cstdio> 2 #include<algorithm> 3 #define Rint register int 4 using namespace std; 5 const int N = 20003; 6 int n, Q, q[4], lans, a[N], id[N], root[N], ls[N << 5], rs[N << 5], cnt; 7 struct Node { 8 int sum, lmax, rmax; 9 inline Node(int s = 0, int l = 0, int r = 0): sum(s), lmax(l), rmax(r){} 10 inline Node operator + (const Node &o) const { 11 return Node(sum + o.sum, max(lmax, sum + o.lmax), max(o.rmax, o.sum + rmax)); 12 } 13 } seg[N << 5]; 14 inline void pushup(int x){ 15 seg[x] = seg[ls[x]] + seg[rs[x]]; 16 } 17 inline void build(int &x, int L, int R){ 18 x = ++ cnt; 19 if(L == R){ 20 seg[x] = Node(1, 1, 1); 21 return; 22 } 23 int mid = L + R >> 1; 24 build(ls[x], L, mid); 25 build(rs[x], mid + 1, R); 26 pushup(x); 27 } 28 inline void change(int &nx, int ox, int L, int R, int pos){ 29 nx = ++ cnt; 30 ls[nx] = ls[ox]; rs[nx] = rs[ox]; 31 if(L == R){ 32 seg[nx] = Node(-1, -1, -1); 33 return; 34 } 35 int mid = L + R >> 1; 36 if(pos <= mid) change(ls[nx], ls[ox], L, mid, pos); 37 else change(rs[nx], rs[ox], mid + 1, R, pos); 38 pushup(nx); 39 } 40 inline Node query(int x, int L, int R, int l, int r){ 41 if(!x || l > r) return Node(); 42 if(l <= L && R <= r) return seg[x]; 43 int mid = L + R >> 1; 44 if(r <= mid) return query(ls[x], L, mid, l, r); 45 else if(mid < l) return query(rs[x], mid + 1, R, l, r); 46 else return query(ls[x], L, mid, l, r) + query(rs[x], mid + 1, R, l, r); 47 } 48 inline int solve(int a, int b, int c, int d){ 49 int l = 1, r = n, mid, tmp; 50 while(l <= r){ 51 mid = l + r >> 1; 52 tmp = query(root[mid], 1, n, a, b).rmax + query(root[mid], 1, n, b + 1, c - 1).sum + query(root[mid], 1, n, c, d).lmax; 53 if(tmp >= 0) l = mid + 1; 54 else r = mid - 1; 55 } 56 return id[r]; 57 } 58 int main(){ 59 scanf("%d", &n); 60 for(Rint i = 1;i <= n;i ++){ 61 scanf("%d", a + i); id[i] = i; 62 } 63 sort(id + 1, id + n + 1, [](int x, int y) -> bool {return a[x] < a[y];}); 64 build(root[1], 1, n); 65 for(Rint i = 1;i < n;i ++) 66 change(root[i + 1], root[i], 1, n, id[i]); 67 scanf("%d", &Q); 68 while(Q --){ 69 for(Rint i = 0;i < 4;i ++){ 70 scanf("%d", q + i); 71 q[i] = (q[i] + lans) % n + 1; 72 } 73 sort(q, q + 4); 74 printf("%d ", lans = a[solve(q[0], q[1], q[2], q[3])]); 75 } 76 }