[国家集训队] 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 
	}
}
posted @ 2021-01-05 19:18  C202044zxy  阅读(92)  评论(0编辑  收藏  举报