陈老师的神题,先拜一下
求中位数用二分的方法很容易想到。
可以想到我们把二分到数x后,把小于x的定义为-1,大于等于x的定义为1,只要求出一个子序列和大于等于0就说明中位数大于等于x(题目中的n/2是向上取整的)
然而之后我并不知道怎么做
一般我们建立主席树都是按照数组下标顺序来建的,这题比较奇葩。
假设我们只需要查询中位数为x的时候,最大的子序列和是否大于等于0,会做吧——直接弄出新数组,想gss那样搞就行了
注意到将整个数组排序之后,二分到相邻的两个答案,新数组只会有几个位置不同,就是将若干个1改为-1,不拿发现改为-1后不会再变为1了,也就是说最多总共只有n个改变值。可以利用这个建主席树!
有了这个后我们只需要询问[a,b-1]的rmax + [b,c]的sum + [c+1,d]的lmax是否大于等于0即可。
#include <vector> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int Maxn = 2000005; int a[Maxn], b[Maxn], T[Maxn]; int son[Maxn][2], q[4]; int st,n,m,Q,i,L,R,Mid,ans; vector <int> e[Maxn]; struct Seg_Tr { int sum, lmax, rmax; } Tree[Maxn]; Seg_Tr operator +(const Seg_Tr &a, const Seg_Tr &b) { Seg_Tr ret; ret.sum = a.sum + b.sum; ret.lmax = max(a.lmax, a.sum+b.lmax); ret.rmax = max(b.rmax, b.sum+a.rmax); return ret; } void init(int &p,int l,int r){ p = ++st; Tree[p].sum = r-l+1; Tree[p].lmax = r-l+1; Tree[p].rmax = r-l+1; if (l==r) return; int mid = (l+r)>>1; init(son[p][0],l,mid); init(son[p][1],mid+1,r); } void ins(int &p,int q,int l,int r,int k,int L,int R){ if (L>R) {p=q; return;} p = ++st; if (l==r){ Tree[p].sum = -1; Tree[p].lmax = 0; Tree[p].rmax = 0; return; } int mid = (l+r)>>1, t = L; while (t<=R && e[k][t]<=mid) t++; ins(son[p][0],son[q][0],l,mid,k,L,t-1); ins(son[p][1],son[q][1],mid+1,r,k,t,R); Tree[p] = Tree[son[p][0]] + Tree[son[p][1]]; } Seg_Tr query(int p,int l,int r,int L,int R){ if (L>R || L>r || l>R) return (Seg_Tr){0,0,0}; if (L<=l && R>=r) return Tree[p]; int mid = (l+r)>>1; return query(son[p][0],l,mid,L,R) + query(son[p][1],mid+1,r,L,R); } bool Judge(int x){ Seg_Tr LF = query(T[x],1,n,q[0],q[1]-1); Seg_Tr MD = query(T[x],1,n,q[1],q[2]); Seg_Tr RG = query(T[x],1,n,q[2]+1,q[3]); return LF.rmax+MD.sum+RG.lmax >= 0; } int main(){ scanf("%d",&n); for (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 (i=1;i<=n;i++){ a[i] = lower_bound(b+1,b+m+1,a[i])-b; e[a[i]].push_back(i); } init(T[1],1,n); for (i=2;i<=m;i++) ins(T[i],T[i-1],1,n,i-1,0,e[i-1].size()-1); scanf("%d",&Q); while (Q--){ scanf("%d%d%d%d",&q[0],&q[1],&q[2],&q[3]); for (i=0;i<4;i++) q[i] = (q[i]+b[ans])%n+1; sort(q,q+4); L = 1; R = m; while (L<=R){ int Mid = (L+R)>>1; if (Judge(Mid)) ans = Mid, L = Mid+1; else R = Mid-1; } printf("%d\n",b[ans]); } return 0; }