BZOJ2653 middle

16 篇文章 0 订阅
16 篇文章 0 订阅

中位数的话,可以考虑一下二分答案,然后把原序列转成01序列,看0和1的数量谁多就知道答案是大于mid还是小于mid了

这样如果不强制在线可以整体二分

但是强制在线了-_-

好吧,我们考虑维护mid逐渐增长,那么每次会有一些点从0变成1,我们需要的是每次在某一个mid下查询区间的最大连续和之类的东西,那么我们用主席树维护每个mid的时候的01序列即可

#include<iostream>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<bitset>
#include<set>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 20010
#define MAXM 1000010
#define ll long long
#define eps 1e-8
#define MOD 1000000007
#define INF 1000000000
struct data{
	int mnl;
	int mnr;
	int s;
	friend data operator +(data x,data y){
		data z;
		z.s=x.s+y.s;
		z.mnl=min(x.mnl,x.s+y.mnl);
		z.mnr=min(y.mnr,y.s+x.mnr);
		return z;
	}
};
int n,m;
int a[MAXN];
map<int,int>h;
int g[MAXN];
int tls[MAXN],tln,mx;
int p[MAXN];
int rt[MAXN];
int son[MAXM][2];
data v[MAXM];
int tot;
int la;
bool cmp(int x,int y){
	return a[x]<a[y];
}
inline void ud(int x){
	v[x]=v[son[x][0]]+v[son[x][1]];
}
void change(int &x,int xx,int y,int z,int p){
	x=++tot;
	memcpy(son[x],son[xx],sizeof(son[x]));
	if(y==z){
		v[x].s=v[x].mnl=v[x].mnr=-1;
		return ;
	}
	int mid=y+z>>1;
	if(p<=mid){
		change(son[x][0],son[xx][0],y,mid,p);
	}else{
		change(son[x][1],son[xx][1],mid+1,z,p);
	}
	ud(x);
}
void build(int &x,int y,int z){
	x=++tot;
	if(y==z){
		v[x].s=1;
		v[x].mnl=v[x].mnr=0;
		return ;
	}
	int mid=y+z>>1;
	build(son[x][0],y,mid);
	build(son[x][1],mid+1,z);
	ud(x);
}
data ask(int x,int y,int z,int l,int r){
	if(y==l&&z==r){
		return v[x];
	}
	int mid=y+z>>1;
	if(r<=mid){
		return ask(son[x][0],y,mid,l,r);
	}else if(l>mid){
		return ask(son[x][1],mid+1,z,l,r);
	}else{
		return ask(son[x][0],y,mid,l,mid)+ask(son[x][1],mid+1,z,mid+1,r);
	}
}
bool OK(int mid,int x,int y,int xx,int yy){
	int sm,sl,sr;
	sm=ask(rt[mid],1,n,y,xx).s;
	if(x==y){
		sl=0;
	}else{
		sl=ask(rt[mid],1,n,x,y-1).mnr;
	}
	if(xx==yy){
		sr=0;
	}else{
		sr=ask(rt[mid],1,n,xx+1,yy).mnl;
	}
	return sl+sr+sm<=0;
}
int main(){
	int i,x,y,xx,yy;
	int o[10];
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d",&a[i]);
		tls[++tln]=a[i];
	}
	sort(tls+1,tls+tln+1);
	for(i=1;i<=tln;i++){
		if(tls[i]!=tls[i-1]||i==1){
			g[h[tls[i]]=++mx]=tls[i];
		}
	}
	for(i=1;i<=n;i++){
		a[i]=h[a[i]];
		p[i]=i;
	}
	sort(p+1,p+n+1,cmp);
	int wzh=n;
	build(rt[mx+1],1,n);
	for(i=mx;i;i--){
		rt[i]=rt[i+1];
		while(a[p[wzh]]==i&&wzh){
			change(rt[i],rt[i],1,n,p[wzh]);
			wzh--;
		}
	}
	scanf("%d",&m);
	while(m--){
		for(i=1;i<=4;i++){
			scanf("%d",&o[i]);
			((o[i]+=la)%=n)+=1;
		}
		sort(o+1,o+5);
		x=o[1];
		y=o[2];
		xx=o[3];
		yy=o[4];
		int l=1,r=mx;
		int ans;
		while(l<=r){
			int mid=l+r>>1;
			if(OK(mid,x,y,xx,yy)){
				ans=mid;
				l=mid+1;
			}else{
				r=mid-1;
			}
		}
		printf("%d\n",la=g[ans]);
	}
	return 0;
}

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

*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值