[国家集训队]middle
[国家集训队]middle
Description
给你一个长度为n的序列s。 回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。 强制在线
Solution
考虑二分答案,把问题转化成可行性问题,然后发现b+1 - c-1 是一定必选的,另外两边要想最大就是维护一个连续最大子段和
然后每次二分值改变,只会影响线段树上log个位置,于是考虑主席树
#include<bits/stdc++.h> using namespace std; inline int read() { int f = 1 , x = 0; char ch; do { ch = getchar(); if(ch=='-') f=-1; } while(ch<'0'||ch>'9'); do { x=(x<<3) + (x<<1) + ch - '0'; ch = getchar(); }while(ch>='0'&&ch<='9'); return f*x; } const int MAXN = 20000 + 5; int n; struct NUM { int val; int pos; friend bool operator < (NUM a1,NUM a2) { return a1.val < a2.val; } }a[MAXN]; struct P_Tree { int lc,rc; int lmax; int rmax; int sum; }tree[MAXN * 18]; int cnt,root[MAXN]; int q[4]; inline void pushup(int rt) { tree[rt].sum = tree[tree[rt].lc].sum + tree[tree[rt].rc].sum; tree[rt].lmax = max(tree[tree[rt].lc].lmax,tree[tree[rt].rc].lmax+tree[tree[rt].lc].sum); tree[rt].rmax = max(tree[tree[rt].rc].rmax,tree[tree[rt].lc].rmax+tree[tree[rt].rc].sum); } inline void build(int &rt,int l,int r) { if(!rt) rt = ++cnt; if(l == r) { tree[rt].lmax = tree[rt].rmax = tree[rt].sum = 1; return; } int mid = (l + r) >> 1; build(tree[rt].lc,l,mid); build(tree[rt].rc,mid+1,r); pushup(rt); } inline void insert(int &rt,int rt1,int l,int r,int k) { if(!rt) rt = ++cnt; tree[rt] = tree[rt1]; if(l == r) { tree[rt].sum = -1; tree[rt].lmax = -1; tree[rt].rmax = -1; return; } int mid = (l + r) >> 1; if(mid >= k) tree[rt].lc = 0,insert(tree[rt].lc,tree[rt1].lc,l,mid,k); else tree[rt].rc = 0,insert(tree[rt].rc,tree[rt1].rc,mid+1,r,k); pushup(rt); } inline int query3(int rt,int l,int r,int L,int R) { if(L<=l&&R>=r) return tree[rt].sum; if(L>r||l>R) return 0; int mid = (l + r) >> 1; return query3(tree[rt].lc,l,mid,L,R) + query3(tree[rt].rc,mid+1,r,L,R); } inline int query1(int rt,int l,int r,int L,int R) { if(L<=l&&R>=r) return tree[rt].rmax; //if(L>r||l>R) return 0; int mid = (l + r) >> 1; if(R <= mid) return query1(tree[rt].lc,l,mid,L,R); else if(L >= mid + 1) return query1(tree[rt].rc,mid+1,r,L,R); return max(query1(tree[rt].rc,mid+1,r,mid+1,R),query3(tree[rt].rc,mid+1,r,mid+1,R) + query1(tree[rt].lc,l,mid,L,mid)); } inline int query2(int rt,int l,int r,int L,int R) { if(L<=l&&R>=r) return tree[rt].lmax; // if(L>r||l>R) return 0; int mid = (l + r) >> 1; if(R <= mid) return query2(tree[rt].lc,l,mid,L,R); else if(L >= mid + 1) return query2(tree[rt].rc,mid+1,r,L,R); return max(query2(tree[rt].lc,l,mid,L,mid),query3(tree[rt].lc,l,mid,L,mid) + query2(tree[rt].rc,mid+1,r,mid+1,R)); } inline bool check(int mid) { int res = 0; res = query1(root[mid],1,n,q[0],q[1]) + query2(root[mid],1,n,q[2],q[3]); if(q[2]-1 >= q[1] + 1) res += query3(root[mid],1,n,q[1]+1,q[2]-1); return res >= 0; } int main() { n = read(); for(int i=1;i<=n;i++) a[i].val = read(),a[i].pos = i; sort(a+1,a+n+1); build(root[1],1,n); for(int i=2;i<=n+1;i++) insert(root[i],root[i-1],1,n,a[i-1].pos); int Q = read(),lastans = 0; while(Q--) { int A = read(),B = read(),C = read(),D = read(); q[0] = (A + lastans) % n + 1,q[1] = (B + lastans) % n + 1,q[2] = (C + lastans) % n + 1,q[3] = (D + lastans) % n + 1; sort(q,q+4); int l = 1,r = n + 1,ans = 0; while(l <= r) { int mid = (l + r) >> 1; if(check(mid)) l = mid + 1,ans = mid; else r = mid - 1; } lastans = a[ans].val; printf("%d\n",lastans); } }