\(\sf{Description}\)
\(\sf{Solution}\)
首先如果让你求 \([l,r]\) 区间的中位数是很好算的:具体就是搞一棵主席树,然后二分中位数并算出它在区间的排名用于检验。
可这道题是不定区间,我们二分的中位数实际上算不出排名。
既然区间是不定的,我们可以考虑合法区间需要满足什么条件,再找出那个区间。问题可以转化成二分一个 \(\rm mid\),求出所有左端点在 \([a,b]\) 之间,右端点在 \([c,d]\) 之间的区间的 大于等于 \(\rm mid\) 的值的个数减去小于 \(\rm mid\) 的值的个数(令这个值为 \(val\))的最大值。如果这个最大值 \(\ge 0\),\(\rm mid\) 可能是中位数,增大 \(\rm mid\);反之不可能,减小 \(\rm mid\)。
\([b+1,c-1]\) 里面的数肯定要取,那么接着考虑的就是找出 \(x,y\),使 \([x,b],[c,y]\) 区间的 \(val\) 的和最大。由于那两个区间我们分别知道了右端点和左端点,所以就是求后缀/前缀最大。
如何求 \(val\)?有个很经典的套路:在原序列将比 \(\rm mid\) 小的数的位置赋值为 \(-1\),大于等于 \(\rm mid\) 的位置赋值为 \(1\)。这样查询 \([l,r]\) 的权值和就是 \(val\) 值。
我们注意到如果将 \(\rm mid\) 移到 \(\rm mid+1\),实际上只有值为 \(\rm mid\) 的下标从 \(1\) 变成了 \(-1\)。
所以用可持久化线段树就行了,空间复杂度 \(n\log n\),时间复杂度 \(\mathcal O(q\log^2n)\)。
\(\text{Q&A}\)
\(\text Q_1\):不会出现二分的数不在区间内吗?
\(\text A_1\):区间内会有大于二分值的数满足这个条件,我们继续往上调二分值,一定会在区间内。
\(\text Q_2\):如何处理权值相等的情况?
\(\text A_2\):将权值排序后,可以直接强制权值相等的大小关系。为什么是对的?首先这不影响权值与不同权值的大小关系,其次二分是一定可以分到正确的那个位置的。
\(\sf{Code}\)
在实现时,Query() 函数不能这样写:
node Query(int o,int l,int r,int L,int R) {
    if(l>R or r<L) return (node){0,0,0};
    // more...
    return Query(ls[o],l,mid,L,R)+Query(rs[o],mid+1,r,L,R);
}
因为可能会遍历到不在 \([L,R]\) 的区间,但是不能返回 (node){0,0,0},这样会把原来的 \(-1\) 变成 \(1\),其实就是 return 时应该设一个更小的值。
#include <cstdio>
#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y)
template <class T> inline T read(const T sample) {
    T x=0; int f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}
template <class T> inline void write(const T x) {
    if(x<0) return (void) (putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
template <class T> inline T fab(const T x) {return x>0?x:-x;}
template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=2e4+5;
int n,lastans,val[maxn],p[maxn],rt[maxn],q,num[5];
namespace PDT {
	int son[maxn*20][2],siz;
    struct node {
        int lmax,rmax,sum;
        node operator + (node t) {
            return (node) {
                Max(lmax,sum+t.lmax),
                Max(rmax+t.sum,t.rmax),
                sum+t.sum
            };
        }
    } t[maxn*20];
    void Build(int &o,int l,int r) {
        o=++siz;
        if(l>=r) return (void)(t[o]=(node){1,1,1});
        int mid=l+r>>1;
        Build(son[o][0],l,mid); Build(son[o][1],mid+1,r);
        t[o]=t[son[o][0]]+t[son[o][1]];
    }
    void Insert(int &o,int pre,int l,int r,int pos) {
        o=++siz;
        if(l>=r) return (void)(t[o]=(node){-1,-1,-1});
        int mid=l+r>>1;
        if(pos<=mid) son[o][1]=son[pre][1],Insert(son[o][0],son[pre][0],l,mid,pos);
        else son[o][0]=son[pre][0],Insert(son[o][1],son[pre][1],mid+1,r,pos);
        t[o]=t[son[o][0]]+t[son[o][1]];
    }
    node Query(int o,int l,int r,int L,int R) {
    	if(L>R) return (node){0,0,0};
        if(l>=L&&r<=R) return t[o];
        int mid=l+r>>1;
        if(R<=mid) return Query(son[o][0],l,mid,L,R);
        if(L>mid) return Query(son[o][1],mid+1,r,L,R);
        return Query(son[o][0],l,mid,L,R)+Query(son[o][1],mid+1,r,L,R);
    }
}
bool cmp(int x,int y) {
	return val[x]<val[y];
}
bool ok(int x) {
	int ans1=PDT::Query(rt[x],1,n,num[1]+1,num[2]-1).sum;
	int ans2=PDT::Query(rt[x],1,n,num[0],num[1]).rmax;
	int ans3=PDT::Query(rt[x],1,n,num[2],num[3]).lmax;
	return ((ans1+ans2+ans3)>=0);
}
int main() {
	n=read(9);
	rep(i,1,n) val[i]=read(9),p[i]=i;
	sort(p+1,p+n+1,cmp);
    PDT::Build(rt[1],1,n);
    rep(i,2,n) PDT::Insert(rt[i],rt[i-1],1,n,p[i-1]);
    q=read(9);
    while(q--) {
        rep(i,0,3) num[i]=(lastans+read(9))%n;
        sort(num,num+4);
        rep(i,0,3) ++num[i];
        int l=1,r=n,mid;
        while(l<=r) {
            mid=l+r>>1; 
            if(ok(mid)) lastans=mid,l=mid+1;
            else r=mid-1; 
        }
        print(val[p[lastans]],'\n');
        lastans=val[p[lastans]];
    }
	return 0;
}
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号