【集训队互测 2012】Middle

来源:互联网 发布:淘宝天猫交易额 编辑:程序博客网 时间:2024/06/14 08:57

Description

给出一个序列A,长度为n。给出m次询问,每次询问a,b,c,d(a< b< c< d),求a<=l<=b,c<=r<=d的子序列中,最大的中位数是多少。(这里说的中位数就是中间的那个数)强制在线。
n<=20000,m<=25000

Solution

不知道有什么数据结构能维护中位数。
考虑二分答案,答案x合法就是存在一个序列,使得大于等于x的数的个数大于小于x的数的个数。
那我们可以吧每一个大于等于x的数看做1,小于x的数看做-1。那么一个序列合法就是它的和>=0。
那我们就相当于求一个左端点在[a~b],右端点在[c~d]的最大子段和。
如果这东西>=0,那么答案合法。
这个东西可以拆分成[a~b]的最大后缀和,[b+1~c-1]的和,和[c~d]最大前缀和。
线段树维护。
那么怎么在时限内建树呢?
发现每一个相邻的x的变化只有一条链,于是可以打可持久化线段树。(动态开节点)

Code

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define N 20005using namespace std;struct note{int v,w;}a[N];struct node{int s,lv,rv,l,r;}t[N*30];bool cmp(note x,note y) {return x.v<y.v;}int ans,tot,n,m,x,root[N],q[4];void back(int v) {    int x=t[v].l,y=t[v].r;    t[v].s=t[x].s+t[y].s;    t[v].lv=max(t[x].lv,t[x].s+t[y].lv);    t[v].rv=max(t[y].rv,t[y].s+t[x].rv);}node merge(node y,node z) {    node x;    x.s=y.s+z.s;    x.lv=max(y.lv,y.s+z.lv);    x.rv=max(z.rv,z.s+y.rv);    return x;}void build(int &v,int l,int r) {    v=++tot;    if (l==r) {t[v].s=t[v].lv=t[v].rv=1;return;}    int m=(l+r)/2;    build(t[v].l,l,m);build(t[v].r,m+1,r);    back(v);}void change(int &v,int l,int r,int x) {    t[++tot]=t[v];v=tot;    if (l==r) {t[v].s=t[v].lv=t[v].rv=-1;return;}    int m=(l+r)/2;    if (x<=m) change(t[v].l,l,m,x);    else change(t[v].r,m+1,r,x);    back(v);}node find(int v,int l,int r,int x,int y) {    if (x>y) return t[0];    if (l==x&&r==y) return t[v];    int m=(l+r)/2;    if (y<=m) return find(t[v].l,l,m,x,y);    else if (x>m) return find(t[v].r,m+1,r,x,y);    else return merge(find(t[v].l,l,m,x,m),find(t[v].r,m+1,r,m+1,y));}bool check(int x) {    return find(root[x],1,n,q[0],q[1]).rv+find(root[x],1,n,q[1]+1,q[2]-1).s+    find(root[x],1,n,q[2],q[3]).lv>=0;}int main() {    scanf("%d",&n);    fo(i,1,n) scanf("%d",&a[i].v),a[i].w=i;    sort(a+1,a+n+1,cmp);    build(root[1],1,n);    fo(i,2,n) root[i]=root[i-1],change(root[i],1,n,a[i-1].w);    for(scanf("%d",&m);m;m--) {        fo(i,0,3) scanf("%d",&x),q[i]=(ans+x)%n+1;sort(q,q+4);        int l=1,r=n+1,mid;        while (l<r) {            mid=(l+r)/2;            if (check(mid)) l=mid+1;else r=mid;        }        printf("%d\n",ans=a[l-1].v);    }}
0 0