BZOJ 2653: middle

2653: middle

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 1536  Solved: 855
[Submit][Status][Discuss]

Description

  一个长度为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]。
  输入保证满足条件。

 

Output

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

 

Sample Input

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

271451044
271451044
969056313

Sample Output

 

HINT

 

  0:n,Q<=100

  1,...,5:n<=2000

  0,...,19:n<=20000,Q<=25000


 

 

Source

分析:

首先我们大概都能够想到二分答案然后判断...

怎么判断?一个很经典的思想,我才不会告诉你我没有想到QAQ...

对于一个序列S,设其中位数位M,二分答案位ans,如果M>=ans,那么一定满足S中有大于等于$\frac{|S|}{2}$的数字大于等于ans,所以我们需要在给顶序列中寻找合法的子序列使得存在M>=ans,我们可以把大于等于ans的数字置成1,小于ans的数字置为0,然后问题就转化为了在合法序列中寻找最大子段和使得其大于等于0...这就是基础的线段树问题,但是这样我们就需要n个线段树,很显然这是不兹磁的...所以我们先把ans=1(离散化之后)的线段树建出来,也就是说每个位置都是1,然后对于以后的i,用可持久化线段树单点修改压空间...查询的时候就在对应的线段树上查询即可...

代码:

不要问我为什么我要手写lower_bound还写得这么鬼畜...因为我开心...调都没调就A了...

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
//by NeighThorn
using namespace std;

const int maxn=20000+5,maxm=7000000+5;

int n,q,len,tot,ls[maxm],rs[maxm],sum[maxm],lmax[maxm],rmax[maxm],root[maxn];

long long a[maxn],mp[maxn];

vector<int> M[maxn];

inline int find(long long _){
	int __=1,___=len,____;
	while(__<=___){
		int _____=(__+___)>>1;
		if(mp[_____]>=_)
			____=_____,___=_____-1;
		else
			__=_____+1;
	}
	return ____;
}

inline void build(int l,int r,int &x){
	x=++tot;
	if(l==r){
		lmax[x]=rmax[x]=sum[x]=1;
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,ls[x]),build(mid+1,r,rs[x]);
	sum[x]=sum[ls[x]]+sum[rs[x]];
	lmax[x]=max(lmax[ls[x]],sum[ls[x]]+lmax[rs[x]]);
	rmax[x]=max(rmax[rs[x]],sum[rs[x]]+rmax[ls[x]]);
}

inline void change(int l,int r,int x,int &y,int pos,int val){
	y=++tot;
	if(l==r){
		lmax[y]=rmax[y]=sum[y]=val;
		return;
	}
	int mid=(l+r)>>1;ls[y]=ls[x],rs[y]=rs[x];
	if(pos<=mid)
		change(l,mid,ls[x],ls[y],pos,val);
	else
		change(mid+1,r,rs[x],rs[y],pos,val);
	sum[y]=sum[ls[y]]+sum[rs[y]];
	lmax[y]=max(lmax[ls[y]],sum[ls[y]]+lmax[rs[y]]);
	rmax[y]=max(rmax[rs[y]],sum[rs[y]]+rmax[ls[y]]);
}

inline int querysum(int l,int r,int L,int R,int x){
	if(l==L&&r==R)
		return sum[x];
	int mid=(l+r)>>1;
	if(R<=mid)
		return querysum(l,mid,L,R,ls[x]);
	else if(L>mid)
		return querysum(mid+1,r,L,R,rs[x]);
	else
		return querysum(l,mid,L,mid,ls[x])+querysum(mid+1,r,mid+1,R,rs[x]);
}

inline int queryrmax(int l,int r,int L,int R,int x){
	if(l==L&&r==R)
		return rmax[x];
	int mid=(l+r)>>1;
	if(R<=mid)
		return queryrmax(l,mid,L,R,ls[x]);
	else if(L>mid)
		return queryrmax(mid+1,r,L,R,rs[x]);
	else
		return max(queryrmax(l,mid,L,mid,ls[x])+querysum(mid+1,r,mid+1,R,rs[x]),queryrmax(mid+1,r,mid+1,R,rs[x]));
}

inline int querylmax(int l,int r,int L,int R,int x){
	if(l==L&&r==R)
		return lmax[x];
	int mid=(l+r)>>1,ans;
	if(R<=mid)
		return querylmax(l,mid,L,R,ls[x]);
	else if(L>mid)
		return querylmax(mid+1,r,L,R,rs[x]);
	else
		return max(querylmax(mid+1,r,mid+1,R,rs[x])+querysum(l,mid,L,mid,ls[x]),querylmax(l,mid,L,mid,ls[x]));
}

signed main(void){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]),mp[i]=a[i];
	sort(mp+1,mp+n+1),len=unique(mp+1,mp+n+1)-mp-1;
	for(int i=1;i<=n;i++)
		a[i]=find(a[i]),M[a[i]].push_back(i);
	build(1,n,root[1]);
	for(int i=2;i<=len;i++)
		if(M[i-1].size()>0){
			change(1,n,root[i-1],root[i],M[i-1][0],-1);
			for(int j=0;j<M[i-1].size();j++)
				change(1,n,root[i],root[i],M[i-1][j],-1);
		}
	scanf("%d",&q);long long ans=0,a[4];
	for(int i=1;i<=q;i++){
		for(int j=0;j<4;j++)
			scanf("%lld",&a[j]),a[j]=(a[j]+ans)%n,a[j]++;
		sort(a,a+4);
		int l=1,r=len;
		while(l<=r){
			int mid=(l+r)>>1;
			int lm=queryrmax(1,n,a[0],a[1],root[mid]);
			int s=0;
			if(a[1]+1<=a[2]-1)
				s=querysum(1,n,a[1]+1,a[2]-1,root[mid]);
			int rm=querylmax(1,n,a[2],a[3],root[mid]);
			if(lm+s+rm>=0)
				ans=mid,l=mid+1;
			else
				r=mid-1;
		}ans=mp[ans];
		printf("%d\n",ans);
	}
	return 0;
}

  


By NeighThorn

posted @ 2017-02-14 20:11  NeighThorn  阅读(170)  评论(0编辑  收藏  举报