BZOJ2653 middle 【主席树+二分】

BZOJ


SOL

无法确定中位数 ? 我们可以考虑转化思路。
二分一个中位数,再判断是否合理。

根据本题中中位数的定义,只需要小于 它的 数的个数 ≤ ∣ l e n 2 ∣ \le |{len \over2}| 2len
我们可以将大于 i i i的数赋值成 1 1 1,小于的赋值成 − 1 -1 1
若 m a x L s u m [ a , b − 1 ] + s u m [ b , c ] + m a x R s u m [ c + 1 , d ] ≥ 0 若maxLsum[a,b-1]+sum[b,c]+maxRsum[c+1,d]\ge0 maxLsum[a,b1]+sum[b,c]+maxRsum[c+1,d]0 i i i可能可以更大。

如何实现赋值操作 ? 用主席树增量法更改。
从小到大排序,对于“下一个数的主席树”,把当前数从 1 1 1改为 − 1 -1 1即可。

代码好懂。


CODE

#include<bits/stdc++.h>
#define pf printf
#define sf scanf
#define cs const
#define ll long long
#define db double
#define ri register int
using namespace std;
#define in red()
inline int red()
{
    int data=0;int w=1; char ch=0;
    ch=getchar();
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
cs int N=1e6+10,M=2e4+10;
#define lc(x) ch[x][0]
#define rc(x) ch[x][1]
int ch[N][2],rt[M],n,m,tot=0;
struct node{
	int sum,lm,rm;
}val[N];
inline node merge(node a,node b){
	node t;
	t.sum=a.sum+b.sum;
	t.lm=max(a.lm,a.sum+b.lm);
	t.rm=max(b.rm,b.sum+a.rm);
	return t;
}
inline int cpy(int x){++tot;ch[tot][0]=ch[x][0];ch[tot][1]=ch[x][1];return tot;}
inline void build(int l,int r,int &t){
	t=++tot;
	if(l==r)return val[t].lm=val[t].rm=val[t].sum=1,void();
	int mid=(l+r)>>1;
	build(l,mid,lc(t));build(mid+1,r,rc(t));
	val[t]=merge(val[lc(t)],val[rc(t)]);
}
inline void insert(int p,int l,int r,int k,int &t){
	t=cpy(p);
	if(l==r)return val[t].lm=val[t].rm=val[t].sum=-1,void();
	int mid=(l+r)>>1;
	if(k<=mid)insert(lc(p),l,mid,k,lc(t));
	else insert(rc(p),mid+1,r,k,rc(t));
	val[t]=merge(val[lc(t)],val[rc(t)]);
}
inline node query(int p,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr)return val[p];
	int mid=(l+r)>>1;
	if(qr<=mid)return query(lc(p),l,mid,ql,qr);
	else if(ql>mid)return query(rc(p),mid+1,r,ql,qr);
	else return merge(query(lc(p),l,mid,ql,qr),query(rc(p),mid+1,r,ql,qr));
}
typedef pair<int,int> pi;
#define fi first
#define se second
pi a[M];
int q[4];
inline bool check(int k){
	return query(rt[k],1,n,q[1],q[2]).sum+max(0,query(rt[k],1,n,q[0],q[1]-1).rm)+max(0,query(rt[k],1,n,q[2]+1,q[3]).lm)>=0;
}
inline int run(){
	int l=1,r=n,mid;
	while(l+1<r){
		mid=(l+r)>>1;
		if(check(mid))l=mid;
		else r=mid;
	}
	return check(r) ? r : l;
}

signed main (){
	n=in;
	for(ri i=1;i<=n;++i){
		a[i].fi=in;a[i].se=i;
	}
	sort(a+1,a+n+1);
	build(1,n,rt[1]);
	for(ri i=1;i<=n;++i)insert(rt[i],1,n,a[i].se,rt[i+1]);
	m=in;
	int ans=0;
	while(m--){
		for(ri i=0;i<4;++i)q[i]=in,q[i]=(q[i]+ans)%n+1;
		sort(q,q+4);
		cout<<(ans=a[run()].fi)<<'\n';
	}
	   return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值