【集训队互测 2012】Middle

来源:互联网 发布:淘宝违规扣分30分 编辑:程序博客网 时间:2024/06/07 13:43

Description

一个长度为 n 的序列 a ,设其排过序之后为 b ,其中位数定义为 b[n/2] ,其中 a,b 从 0 开始标号 , 除法取下整。
给你一个长度为 n 的序列 s 。回答 Q 个这样的询问 : s 的左端点在 [a,b] 之间 , 右端点在 [c,d] 之间的子序列中 ,最大的中位数。
其中 a

Solution

怎么做

一看到什么中位数,k小数,数据范围又不大,那么就可以二分出一个mid,找出比mid小的个数有多少个。
因为每个数对当前判断的贡献只有是与不是,去或不去,那么用1或-1规划一下就好了。比mid的小的设为-1,否则设为1,那么区间[l…r]中如果中位数为mid那么就是这些1和-1的和加起来≥0。
因为b到c必须要取,所以把区间拆解一下变成[a..b]中的最长后缀和+[a+1…b-1]的和+[c…d]中的最长前缀和。

用什么?

强制在线,那么就是可持久化结构。还支持询问,取max。
可持久化线段树。

Code

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=20007;int i,j,k,l,n,m,ans,data[maxn],u,v,r,mid,num,tt;int root[maxn],q[5];struct node{    int lda,sum,l,r,rda;}t[25000*30],op;struct nod{    int a,b;}a[maxn];bool cmp(nod x,nod y){    return x.a<y.a;}int read(){    int x=0,f=-1;    char ch=getchar();    while(ch<'0'||ch>'9'){        if(ch='-')f=-1;        ch=getchar();    }    while(ch>='0'&&ch<='9'){        x=x*10+ch-'0';        ch=getchar();    }    return x;}void merge(int x){    t[x].sum=t[t[x].l].sum+t[t[x].r].sum;    t[x].lda=max(t[t[x].l].lda,t[t[x].l].sum+t[t[x].r].lda);    t[x].rda=max(t[t[x].r].rda,t[t[x].r].sum+t[t[x].l].rda);}void build(int &x,int l,int r){    if(!x)x=++num;    if(l==r){        t[x].lda=t[x].sum=t[x].rda=1;    }    else{        int mid=(l+r)/2;        build(t[x].l,l,mid);        build(t[x].r,mid+1,r);        merge(x);    }}void change(int &x,int l,int r,int y){    t[++num]=t[x];x=num;    if(l==r){t[x].lda=t[x].sum=t[x].rda=-1;return;}    int mid=(l+r)/2;    if(y<=mid)change(t[x].l,l,mid,y);    else change(t[x].r,mid+1,r,y);    merge(x);}node bing(node x,node y){    node z;    z.sum=x.sum+y.sum;    z.l=x.l;z.r=y.r;    z.lda=max(x.lda,x.sum+y.lda);    z.rda=max(y.rda,y.sum+x.rda);    return z;}node find(int x,int l,int r,int y,int z){    if(y>z)return op;    if(l==y&&r==z){        return t[x];    }    else{        int mid=(l+r)/2;        if(z<=mid)return find(t[x].l,l,mid,y,z);        else if (y>mid)return find(t[x].r,mid+1,r,y,z);        else{            return bing(find(t[x].l,l,mid,y,mid),find(t[x].r,mid+1,r,mid+1,z));            }    }}int pan(int x){    return find(root[x],1,n,q[1],q[2]).rda+find(root[x],1,n,q[2]+1,q[3]-1).sum    +find(root[x],1,n,q[3],q[4]).lda;    }int main(){    n=read();    fo(i,1,n){        a[i].a=read();        a[i].b=i;    }    sort(a+1,a+1+n,cmp);    build(root[1],1,n);    fo(i,2,n){        root[i]=root[i-1];        change(root[i],1,n,a[i-1].b);    }    m=read();    fo(i,1,m){        k=read();tt=read();u=read();v=read();        q[1]=(k+ans)%n+1;q[2]=(tt+ans)%n+1;q[3]=(u+ans)%n+1;q[4]=(v+ans)%n+1;        sort(q+1,q+5);        l=1,r=n;        while(l<r){            mid=(l+r+1)/2;            int pp=pan(mid);            if(pp>=0)l=mid;else r=mid-1;        }        ans=a[l].a;        printf("%d\n",ans);    }}
1 0