[国家集训队] middle
一、题目
二、解法
我一开始的思路是枚举中位数,然后看它是否能成为中位数。如果我们把小于他的数看成 \(-1\) ,大于等于他的数看成 \(1\) ,那么当序列权值 \(\geq0\) 的时候中位数是大于等于它的,暴力实现这个过程是 \(O(n^2q)\) 的。因为要枚举中位数,还要求 \([l_1,r_1)\) 的最大后缀和 \((l_2,r_2]\) 的最大前缀,两个各耗时 \(O(n)\) ,由于强制在线我们只能对他们都下手。
枚举中位数怎么优化呢?细想一下满足单调性,那我们可以套一个二分嘛,恭喜你解决掉了一个 \(O(n)\)
但是这个求最大前缀 \(/\) 后缀就有一些麻烦了,因为每个数当中位数时所对应的各个位置的权值是不同的。有一个极其暴力的思路就是对每一个中位数都开一个数据结构(比如线段树),然后查询,但是难在预处理耗时太大。
上述思路其实是可以延续的,考虑两个排序后相邻的数当中位数时他们两个的线段树是差不多的,差别可能就是某些位置由 \(1\) 变成了 \(-1\) ,那么我们可以用主席树来保存所有的线段树,因为每次修改的很少所以复杂度是对的,等于说我们用主席树完成了开 \(n\) 棵线段树的功能
时间复杂度 \(O(q\log^2n)\)
#include <cstdio>
#include <algorithm>
using namespace std;
const int M = 20005;
const int N = 50*M;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,q,cnt,ans,p[4],rt[M],b[M],ls[N],rs[N];
struct node
{
int x,id;
bool operator < (const node &b) const
{
return x<b.x;
}
}a[M];
struct data
{
int l,r,sum;
data operator + (const data &b) const
{
return data{max(l,sum+b.l),max(b.r,b.sum+r),sum+b.sum};
}
}tr[N],emp;
void build(int &x,int l,int r)
{
x=++cnt;
if(l==r)
{
tr[x].l=tr[x].r=tr[x].sum=1;
return ;
}
int mid=(l+r)>>1;
build(ls[x],l,mid);
build(rs[x],mid+1,r);
tr[x]=tr[ls[x]]+tr[rs[x]];
}
void ins(int &x,int y,int l,int r,int id,int f)
{
x=++cnt;tr[x]=tr[y];
ls[x]=ls[y];rs[x]=rs[y];
if(l==r)
{
tr[x].l=tr[x].r=tr[x].sum=f;
return ;
}
int mid=(l+r)>>1;
if(mid>=id) ins(ls[x],ls[y],l,mid,id,f);
else ins(rs[x],rs[y],mid+1,r,id,f);
tr[x]=tr[ls[x]]+tr[rs[x]];
}
data ask(int x,int l,int r,int L,int R)
{
if(L>r || l>R) return emp;
if(L<=l && r<=R) return tr[x];
int mid=(l+r)>>1;
return ask(ls[x],l,mid,L,R)+ask(rs[x],mid+1,r,L,R);
}
int check(int x)
{
int res=ask(rt[x],1,n,p[0],p[1]-1).r;
res+=ask(rt[x],1,n,p[2]+1,p[3]).l;
res+=ask(rt[x],1,n,p[1],p[2]).sum;
return res>=0;
}
void dich(int l,int r)
{
if(l>r) return ;
int mid=(l+r)>>1;
if(check(mid))
{
ans=mid;
dich(mid+1,r);
}
else dich(l,mid-1);
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
a[i]=node{read(),i};
sort(a+1,a+1+n);
build(rt[1],1,n);
int las=rt[1];
for(int i=1,j;i<=n;i=j)
{
j=i;m++;
for(;j<=n && a[j].x==a[i].x;j++)
{
b[m]=a[j].x;
ins(rt[m+1],las,1,n,a[j].id,-1);
las=rt[m+1];//以前写错了
}
}
q=read();
while(q--)
{
for(int i=0;i<4;i++) p[i]=(read()+ans)%n+1;
sort(p,p+4);
dich(1,m);
printf("%d\n",b[ans]);
ans=b[ans];//surprise mother fu**er
}
}