[国家集训队]middle
题目描述
一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。
位置也从0开始标号。
我会使用一些方式强制你在线。
输入输出格式
输入格式:
第一行序列长度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]。
输入保证满足条件。
输出格式:
Q行依次给出询问的答案。
5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
输出样例#1:
271451044
271451044
969056313
说明
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。 强制在线。
一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。
位置也从0开始标号。
我会使用一些方式强制你在线。
输入输出格式
输入格式:
第一行序列长度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]。
输入保证满足条件。
输出格式:
Q行依次给出询问的答案。
输入输出样例
5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
输出样例#1:
271451044
271451044
969056313
说明
暴力过不了
题意还是比较好理解的
嗯哼,现在让我们进入正题。
做完这题超爽♂
好吧,还是让我写一下题意
题意:给你一个长度为n的序列s。回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。 强制在线。
这一题对于一个我这个刚学主席树不到两天的人简直就是作死。
思路:首先考虑二分答案,判断可行的方法则是看是否大于他的数可以比小于他的数多。则考虑对于[b, c]直接求出来(因为不管怎么取都会取到这一段),对于[a, b-1]求最大的后缀(带有一点贪心思想),[c+1, d]求最大前缀,可以建线段树维护。如果对于每一个数建一个线段树,空间(嘿嘿嘿)就会爆了,所以我们考虑使用主席树维护。
怎么判断大于他的数可以比小于他的数多呢?
这里我们可以用一种比较巧妙的方法,我们把小于当前数的数全部标-1,大于等于的标1,到时只需要维护这个数组就可以了(是不是很棒棒)(手动滑稽)
总的复杂度 O(可以过(手动划去))显然可以(碾过)解决这道题。
下面请出我奇丑无比的代码:
#include<bits/stdc++.h>
using namespace std;
const int N=10000007;
int a[N],ch[N][2],b[N],c[N],tot,n,m,root[N];
struct A{
int id,val;
};
void push(int rt){
a[rt]=a[ch[rt][0]]+a[ch[rt][1]];
b[rt]=max(b[ch[rt][0]]+a[ch[rt][1]],b[ch[rt][1]]); //最大后缀
c[rt]=max(c[ch[rt][0]],c[ch[rt][1]]+a[ch[rt][0]]); //最大前缀
}
void build(int l,int r,int rt){ //奇奇gay gay 的建树
if(l==r){
a[rt]=b[rt]=c[rt]=1;
return;
}
int mid=(l+r)>>1;
tot++;
ch[rt][0]=tot;
build(l,mid,tot);
tot++;
ch[rt][1]=tot;
build(mid+1,r,tot);
push(rt);
}
void insert(int l,int r,int x,int rt){ //奇奇gay gay 的插入♂
if(l==r){
tot++;
a[tot]=b[tot]=c[tot]=-1;
return;
}
int mid=(l+r)>>1;
if(mid>=x){
insert(l,mid,x,ch[rt][0]);
tot++;
ch[tot][0]=tot-1;
ch[tot][1]=ch[rt][1];
push(tot);
}else{
insert(mid+1,r,x,ch[rt][1]);
tot++;
ch[tot][1]=tot-1;
ch[tot][0]=ch[rt][0];
push(tot);
}
}
int q[N],qq[N];
A p[N];
int query(int l,int r,int L,int R,int rt){ //区间和
if(L<=l&&r<=R) return a[rt];
int mid=(l+r)>>1,ret=0;
if(L<=mid) ret+=query(l,mid,L,R,ch[rt][0]);
if(R>mid) ret+=query(mid+1,r,L,R,ch[rt][1]);
return ret;
}
int query1(int l,int r,int L,int R,int rt){ //最大后缀
if(L>R) return 0;
if(L<=l&&r<=R) return b[rt];
int mid=(l+r)>>1,ret=0;
if(L<=mid) ret=query1(l,mid,L,R,ch[rt][0]);
if(R>mid) ret=max(ret+query(mid+1,r,L,R,ch[rt][1]),query1(mid+1,r,L,R,ch[rt][1]));
return ret;
}
int query2(int l,int r,int L,int R,int rt){ //最大前缀
if(L>R) return 0;
if(L<=l&&r<=R) return c[rt];
int mid=(l+r)>>1,ret=0;
if(R>mid) ret=query2(mid+1,r,L,R,ch[rt][1]);
if(L<=mid) ret=max(ret+query(l,mid,L,R,ch[rt][0]),query2(l,mid,L,R,ch[rt][0]));
return ret;
}
int check(int l,int r,int ll,int rr){//毁天灭地的二分答案
int L=1,R=n+1,mid;
while(L+1<R){
mid=(L+R)>>1;
if(max(query1(1,n,l,r-1,root[mid-1]),0)+max(query2(1,n,ll+1,rr,root[mid-1]),0)+query(1,n,r,ll,root[mid-1])>=0)
L=mid; else R=mid;
}
return L;
}
bool cmp(A x,A y){
return x.val<y.val;
}
int k,l,r,ll,rr,pp[5];
vector<int>pq[1000005];
int main(){
cin>>n;
root[0]=0;
build(1,n,root[0]);
for(int i=1;i<=n;i++) scanf("%d",&p[i].val),q[i]=p[i].val,qq[i]=p[i].val,p[i].id=i; //中二的离散化
sort(p+1,p+1+n,cmp);
for(int i=1;i<=n;i++){
insert(1,n,p[i].id,root[i-1]),root[i]=tot;
}
int last=0;
cin>>m;
while(m--){
scanf("%d%d%d%d",&l,&r,&ll,&rr);
pp[0]=(l+last)%n;pp[1]=(r+last)%n;pp[2]=(ll+last)%n;pp[3]=(rr+last)%n;
sort(pp,pp+4);
last=check(pp[0]+1,pp[1]+1,pp[2]+1,pp[3]+1);
last=p[last].val;
printf("%d\n",last);
last%=n;
}
}//一百零八行的结束(拜拜~)