BZOJ2653: middle

BZOJ2653: middle

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]。  
输入保证满足条件。
第一行所谓“排过序”指的是从小到大排序!
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

题解Here!

第一眼看去好不可做啊。。。
考虑二分答案。
假设我们二分出一个值$mid$,把小于它的数设为$-1$,大于它的数设为$1$。
然后对$[a,b]$求最大后缀和,对$[c,d]$求最大前缀和,对$[b+1,c-1]$求和。
如果和大于等于$0$,说明这个数还可以再大一些,否则只能小一些。
至于那个$1,-1$怎么改。。。搞一个主席树就好。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 20010
#define MAX 999999999
using namespace std;
int n,m;
int val[MAXN],id[MAXN];
int size=0,root[MAXN];
struct Chairman_Tree{
	int lsum,rsum,sum,lson,rson;
	Chairman_Tree(){
		lsum=rsum=-MAX;
		sum=0;
	}
	friend Chairman_Tree operator +(const Chairman_Tree p,const Chairman_Tree q){
		Chairman_Tree x;
		x.lsum=max(p.lsum,p.sum+q.lsum);
		x.rsum=max(q.rsum,p.rsum+q.sum);
		x.sum=p.sum+q.sum;
		return x;
	}
}a[MAXN*22];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline bool cmp(const int &p,const int &q){
	return val[p]<val[q];
}
inline void pushup(int rt){
	a[rt].lsum=max(a[a[rt].lson].lsum,a[a[rt].lson].sum+a[a[rt].rson].lsum);
	a[rt].rsum=max(a[a[rt].rson].rsum,a[a[rt].lson].rsum+a[a[rt].rson].sum);
	a[rt].sum=a[a[rt].lson].sum+a[a[rt].rson].sum;
}
int buildtree(int l,int r){
	int rt=++size;
	if(l==r){
		a[rt].sum=a[rt].lsum=a[rt].rsum=r-l+1;
		return rt;
	}
	int mid=l+r>>1;
	a[rt].lson=buildtree(l,mid);
	a[rt].rson=buildtree(mid+1,r);
	pushup(rt);
	return rt;
}
void insert(int k,int l,int r,int &rt){
	a[++size]=a[rt];rt=size;
	if(l==r){
		a[rt].sum=a[rt].lsum=a[rt].rsum=-1;
		return;
	}
	int mid=l+r>>1;
	if(k<=mid)insert(k,l,mid,a[rt].lson);
	else insert(k,mid+1,r,a[rt].rson);
	pushup(rt);
}
Chairman_Tree query(int lside,int rside,int l,int r,int rt){
	if(lside<=l&&r<=rside)return a[rt];
	int mid=l+r>>1;
	Chairman_Tree lson,rson;
	if(lside<=mid)lson=query(lside,rside,l,mid,a[rt].lson);
	if(mid<rside)rson=query(lside,rside,mid+1,r,a[rt].rson);
	return (lson+rson);
}
inline bool check(int l1,int r1,int l2,int r2,int x){
	int s=0;
	Chairman_Tree ans;
	if(r1+1<=l2-1){
		ans=query(r1+1,l2-1,1,n,root[x]);
		s+=ans.sum;
	}
	ans=query(l1,r1,1,n,root[x]);
	s+=ans.rsum;
	ans=query(l2,r2,1,n,root[x]);
	s+=ans.lsum;
	return (s>=0);
}
int solve(int l1,int r1,int l2,int r2){
	int l=1,r=n,ans;
	while(l<=r){
		int mid=l+r>>1;
		if(check(l1,r1,l2,r2,mid)){
			ans=val[id[mid]];
			l=mid+1;
		}
		else r=mid-1;
	}
	return ans;
}
void work(){
	int l1,r1,l2,r2,last=0,q[4];
	while(m--){
		for(int i=0;i<4;i++)q[i]=(read()+last)%n;
		sort(q,q+4);
		l1=q[0]+1;r1=q[1]+1;l2=q[2]+1;r2=q[3]+1;
		last=solve(l1,r1,l2,r2);
		printf("%d\n",last);
	}
}
void init(){
	n=read();
	for(int i=1;i<=n;i++){
		val[i]=read();
		id[i]=i;
	}
	sort(id+1,id+n+1,cmp);
	root[1]=buildtree(1,n);
	for(int i=2;i<=n;i++){
		root[i]=root[i-1];
		insert(id[i-1],1,n,root[i]);
	}
	m=read();
}
int main(){
	init();
	work();
	return 0;
}

 

posted @ 2019-03-31 17:11  符拉迪沃斯托克  阅读(146)  评论(0编辑  收藏  举报
Live2D