bzoj2653

middle

 HYSBZ - 2653 

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

 

Input
第一行序列长度n。接下来n行按顺序给出a中的数。
接下来一行Q。然后Q行每行a,b,c,d,我们令上个询问的答案是
x(如果这是第一个询问则x=0)。
令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
将q从小到大排序之后,令真正的
要询问的a=q[0],b=q[1],c=q[2],d=q[3]。  
输入保证满足条件。
第一行所谓“排过序”指的是从小到大排序!
n<=20000,Q<=25000
 

 

Output

Q行依次给出询问的答案。

 

Sample Input
5
170337785 271451044 22430280 969056313 206452321
3
3 1 0 2
2 3 1 4
3 1 4 0

Sample Output

271451044

271451044

969056313

 

sol : 一个区间的中位数要求这段区间比他大的个数>=比他小的个数,所以我们可以二分答案,对于每个数字建一颗线段树,如[a,b]和[c,d]中的那段区间,就是所有数字中比他大的减去比他小的,在减去[a,b]中的前缀min和[c,d]中的后缀min,但是对于每次都重建一棵树肯定会T出shi,所以弄棵主席树可持久化,先建一个全-1的树,然后按数值大小从大到小做,一次把一个-1改成1,相当于修改一个区间,比如修改位置P,就是改掉[1,P]的后缀min和[P,n]的前缀min

Ps:实现的时候犯错调了好久,详见注释

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0'); return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=20005;
#define pii pair<int,int>
#define fi first
#define se second
int n,m;
struct Shuz
{
    int Num,Pos;
    inline bool operator<(const Shuz &tmp)const
    {
        return Num>tmp.Num;
    }
}A[N];
int rt[N],cnt=0;
struct Node
{
    int ls,rs;
    pii Pre,Suf;
}T[N*105];
inline void PushUp(int x)
{
    T[x].Pre.fi=min(T[T[x].ls].Pre.fi,T[T[x].rs].Pre.fi);
    T[x].Suf.fi=min(T[T[x].ls].Suf.fi,T[T[x].rs].Suf.fi);
}
inline void PushDown(int x)
{
    if((!T[x].Pre.se)&&(!T[x].Suf.se)) return;
    int o1=T[x].Pre.se,o2=T[x].Suf.se;
    int lc=++cnt,rc=++cnt;
    T[lc]=T[T[x].ls]; T[rc]=T[T[x].rs];
    if(o1)
    {
        T[lc].Pre.fi+=o1; T[lc].Pre.se+=o1; T[rc].Pre.fi+=o1; T[rc].Pre.se+=o1;
    }
    if(o2)
    {
        T[lc].Suf.fi+=o2; T[lc].Suf.se+=o2; T[rc].Suf.fi+=o2; T[rc].Suf.se+=o2;
    }
    T[x].ls=lc; T[x].rs=rc;
    T[x].Pre.se=T[x].Suf.se=0;
}
inline void Build(int &x,int l,int r)
{
    x=++cnt;
    T[x].Pre.fi=-r; T[x].Pre.se=0; T[x].Suf.fi=-(n-l+1); T[x].Suf.se=0;
    if(l==r) return;
    int mid=(l+r)>>1;
    Build(T[x].ls,l,mid);
    Build(T[x].rs,mid+1,r);
}
inline void ChgPre(int &x,int y,int l,int r,int ql,int qr)
{
    x=++cnt; T[x]=T[y];
    if(l==ql&&r==qr)
    {
        T[x].Pre.fi+=2; T[x].Pre.se+=2; return;
    }
    PushDown(y); T[x]=T[y]; //要把y中的标记传下去,否则之后把T[y].ls弄回T[x].ls会萎掉!!! 
    int mid=(l+r)>>1;
    if(qr<=mid) ChgPre(T[x].ls,T[y].ls,l,mid,ql,qr);
    else if(ql>mid) ChgPre(T[x].rs,T[y].rs,mid+1,r,ql,qr);
    else ChgPre(T[x].ls,T[y].ls,l,mid,ql,mid),ChgPre(T[x].rs,T[y].rs,mid+1,r,mid+1,qr);
    PushUp(x);
}
inline void ChgSuf(int &x,int y,int l,int r,int ql,int qr)
{
    x=++cnt; T[x]=T[y];
    if(l==ql&&r==qr)
    {
        T[x].Suf.fi+=2; T[x].Suf.se+=2; return;
    }
    PushDown(y); T[x]=T[y];
    int mid=(l+r)>>1;
    if(qr<=mid) ChgSuf(T[x].ls,T[y].ls,l,mid,ql,qr);
    else if(ql>mid) ChgSuf(T[x].rs,T[y].rs,mid+1,r,ql,qr);
    else ChgSuf(T[x].ls,T[y].ls,l,mid,ql,mid),ChgSuf(T[x].rs,T[y].rs,mid+1,r,mid+1,qr);
    PushUp(x);
}
inline int QueryPre(int x,int l,int r,int ql,int qr)
{
    if(l==ql&&r==qr) return T[x].Pre.fi;
    int mid=(l+r)>>1;
    PushDown(x);
    if(qr<=mid) return QueryPre(T[x].ls,l,mid,ql,qr);
    else if(ql>mid) return QueryPre(T[x].rs,mid+1,r,ql,qr);
    else return min(QueryPre(T[x].ls,l,mid,ql,mid),QueryPre(T[x].rs,mid+1,r,mid+1,qr));
    PushUp(x);
}
inline int AskPre(int x,int l,int r,int ql,int qr)
{
    if(qr==1) return 0;
    if(ql==1) return min(QueryPre(x,l,r,ql,qr-1),0);
    return QueryPre(x,l,r,ql-1,qr-1);
}
inline int QuerySuf(int x,int l,int r,int ql,int qr)
{
    if(l==ql&&r==qr) return T[x].Suf.fi;
    int mid=(l+r)>>1;
    PushDown(x);
    if(qr<=mid) return QuerySuf(T[x].ls,l,mid,ql,qr);
    else if(ql>mid) return QuerySuf(T[x].rs,mid+1,r,ql,qr);
    else return min(QuerySuf(T[x].ls,l,mid,ql,mid),QuerySuf(T[x].rs,mid+1,r,mid+1,qr));
    PushUp(x);
}
inline int AskSuf(int x,int l,int r,int ql,int qr)
{
    if(ql==n) return 0;
    if(qr==n) return min(QuerySuf(x,l,r,ql+1,qr),0);
    return QuerySuf(x,l,r,ql+1,qr+1);
}
int main()
{
    freopen("2653.in","r",stdin);
    freopen("2653.out","w",stdout);
    int i,j,ans=0;
    R(n);
    for(i=1;i<=n;i++) A[i]=(Shuz){read(),i};
    sort(A+1,A+n+1);
//    for(i=1;i<=n;i++) cout<<A[i].Num<<' '; puts("");
    Build(rt[0],1,n);
    for(i=1;i<=n;i++)
    {
        int tot;
        ChgPre(tot,rt[i-1],1,n,A[i].Pos,n);
        ChgSuf(rt[i],tot,1,n,1,A[i].Pos);
    }
    R(m);
    for(i=1;i<=m;i++)
    {
        int a,b,c,d,q[5];
        for(j=1;j<=4;j++) q[j]=(read()+ans)%n+1; sort(q+1,q+5); a=q[1]; b=q[2]; c=q[3]; d=q[4];
        int l=1,r=n,pp;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            int tmp=mid-(n-mid); //倒序的
            if((tmp-AskPre(rt[mid],1,n,a,b)-AskSuf(rt[mid],1,n,c,d))>=0) pp=mid,r=mid-1; //注意是倒序的 
            else l=mid+1;
        }
        Wl(ans=A[pp].Num);
//        return 0;
    }
    return 0;
}
/*
input
5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
Output
271451044
271451044
969056313
*/
View Code

 

posted @ 2019-07-15 11:15  yccdu  阅读(176)  评论(0编辑  收藏  举报