[BZOJ 2653] middle

[BZOJ 2653] middle

题意

一个长度为 (n) 的序列 (a) , 设其升序排序之后为 (b) , 其中位数定义为 (b[n/2]), 其中 (a,b)(0) 开始标号,除法取下整.

给你一个长度为 (n) 的序列 (s). 回答 (q) 个这样的询问: (s) 的左端点在 ([a,b]) 之间,右端点在 ([c,d]) 之间的子序列中, 最大的中位数. 其中 (a<b<c<d). 位置也从 (0) 开始标号.

(nle 2 imes 10^4,qle2.5 imes 10^4).

强制在线.

题解

题里面最坑人的大概就是那个下取整又从 (0) 开始标号了...相当于取第 (left lfloor frac n 2 ight floor+1) 个值. 也就是说偶数的情况下取靠后的那个值作为中位数.

顺便在这题里了解了一些中位数处理的操作.

首先对于一个查询我们二分一个答案 (k), 问题转化为能否有一个合乎询问的区间中位数不小于 (k). 我们如果把原数列中满足 (xge k) 的看作 (+1), (x<k) 的看作 (-1), 那么只要有一个区间的和非负就可以满足条件.

那么我们可以用线段树来维护一下区间和以及最大前后缀和. ([b,c]) 部分是必然要选的, 再加上 ([a,b-1]) 的最大后缀和以及 ([c+1,d]) 的最大前缀和即可.

至于这些线段树, 我们可以发现相邻的值对应的线段树差别不大, 只差了值相等的几个地方. 所以我们可以可持久化一下解决.

代码不难写.

参考代码

#include <bits/stdc++.h>

const int MAXN=20010;

struct Node{
	struct Data{
		int sum;
		int lsum;
		int rsum;
		Data(){}
		Data(int a,int b,int c):sum(a),lsum(b),rsum(c){}
		Data friend operator+(const Data& a,const Data& b){
			return Data(
				a.sum+b.sum,
				std::max(a.lsum,a.sum+b.lsum),
				std::max(b.rsum,a.rsum+b.sum)
			);
		}
	};
	int l;
	int r;
	Data v;
	Node* lch;
	Node* rch;
	Node(Node*);
	void Print();
	Node(int,int);
	void Negate(int);
	Data Query(int,int);
};
Node* N[MAXN];

int n;
int q;
int cnt;
int a[MAXN];
int s[MAXN];
std::vector<int> pos[MAXN];

int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",a+i);
		s[i]=a[i];
	}
	std::sort(s+1,s+n+1);
	cnt=std::unique(s+1,s+n+1)-(s+1);
	for(int i=0;i<n;i++){
		a[i]=std::lower_bound(s+1,s+cnt+1,a[i])-s;
		pos[a[i]].push_back(i);
	}
	N[1]=new Node(0,n-1);
	for(int i=1;i<cnt;i++){
		N[i+1]=new Node(N[i]);
		for(auto p:pos[i])
			N[i+1]->Negate(p);
	}
	scanf("%d",&q);
	int lastans=0;
	for(int i=0;i<q;i++){
		int q[4];
		for(int i=0;i<4;i++){
			scanf("%d",q+i);
			(q[i]+=lastans)%=n;
		}
		std::sort(q,q+4);
		int l=1,r=cnt+1;
		while(r-l>1){
			int mid=(l+r)>>1;
			int sum=0;
			if(q[2]-q[1]>1)
				sum+=N[mid]->Query(q[1]+1,q[2]-1).sum;
			sum+=N[mid]->Query(q[0],q[1]).rsum+N[mid]->Query(q[2],q[3]).lsum;
			if(sum>=0)
				l=mid;
			else
				r=mid;
		}
		printf("%d
",lastans=s[l]);
	}
	return 0;
}

Node::Node(Node* p){
	*this=*p;
}

Node::Data Node::Query(int l,int r){
	if(l<=this->l&&this->r<=r)
		return this->v;
	else{
		if(r<=this->lch->r)
			return this->lch->Query(l,r);
		if(this->rch->l<=l)
			return this->rch->Query(l,r);
		return this->lch->Query(l,r)+this->rch->Query(l,r);
	}
}

void Node::Negate(int x){
	if(this->l==this->r)
		this->v=Data(-1,-1,-1);
	else{
		if(x<=this->lch->r){
			this->lch=new Node(this->lch);
			this->lch->Negate(x);
		}
		else{
			this->rch=new Node(this->rch);
			this->rch->Negate(x);
		}
		this->v=this->lch->v+this->rch->v;
	}
}

void Node::Print(){
	if(this==NULL)
		return;
	printf("[%d,%d] {sum=%d,lsum=%d,rsum=%d}
",l,r,v.sum,v.lsum,v.rsum);
	this->lch->Print();
	this->rch->Print();
}

Node::Node(int l,int r):l(l),r(r){
	if(l==r)
		this->v=Data(1,1,1);
	else{
		int mid=(l+r)>>1;
		this->lch=new Node(l,mid);
		this->rch=new Node(mid+1,r);
		this->v=this->lch->v+this->rch->v;
	}
}

原文地址:https://www.cnblogs.com/rvalue/p/10427676.html