题目大意:左右端点分别在某个区间中的子序列的中位数最大值
题解:http://blog.csdn.net/acm_cxlove/article/details/8566093
要求中位数最大,首先二分中位数,然后判断可行不可行。
判断X可行不可行,对于区间内的数,凡是>=X的标为1,否则为-1。这样的话,求一次最大区间和
如果大于等于0,则说明可行。
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=20005;
int sx[N],icnt;
inline int Bin(int x){
return lower_bound(sx+1,sx+icnt+1,x)-sx;
}
int n,a[N];
int root[N],ls[21*N],rs[21*N],lsum[21*N],rsum[21*N],sum[21*N];
int rcnt,ncnt;
int ed[N];
struct abcd{
int x,y;
abcd(int x=0,int y=0):x(x),y(y) { }
bool operator < (const abcd &B) const{
return x<B.x;
}
}temp[N];
inline void update(int x){
sum[x]=sum[ls[x]]+sum[rs[x]];
lsum[x]=max(lsum[ls[x]],sum[ls[x]]+lsum[rs[x]]);
rsum[x]=max(rsum[rs[x]],rsum[ls[x]]+sum[rs[x]]);
}
void Build(int &x,int l,int r,int t){
x=++ncnt; int mid=(l+r)>>1;
if (l==r) { sum[x]=t; lsum[x]=rsum[x]=max(t,0); return; }
Build(ls[x],l,mid,t);
Build(rs[x],mid+1,r,t);
update(x);
}
void Modify(int &y,int x,int l,int r,int t,int f){
y=++ncnt; int mid=(l+r)>>1;
if (l==r) { sum[y]=f; lsum[y]=rsum[y]=max(f,0); return; }
if (t<=mid)
rs[y]=rs[x],Modify(ls[y],ls[x],l,mid,t,f);
else
ls[y]=ls[x],Modify(rs[y],rs[x],mid+1,r,t,f);
update(y);
}
int Sum(int x,int l,int r,int L,int R){
int mid=(l+r)>>1;
if (L<=l && r<=R) return sum[x];
if (R<=mid)
return Sum(ls[x],l,mid,L,R);
else if (L>mid)
return Sum(rs[x],mid+1,r,L,R);
else
return Sum(ls[x],l,mid,L,mid)+Sum(rs[x],mid+1,r,mid+1,R);
}
int lis[N],lcnt;
void divi(int x,int l,int r,int L,int R){
int mid=(l+r)>>1;
if (L<=l && r<=R){
lis[++lcnt]=x; return;
}
if (R<=mid)
divi(ls[x],l,mid,L,R);
else if (L>mid)
divi(rs[x],mid+1,r,L,R);
else
divi(ls[x],l,mid,L,mid),divi(rs[x],mid+1,r,mid+1,R);
}
int LQ(int x,int L,int R){
lcnt=0;
divi(x,1,n,L,R);
int tmp=0,ret=0;
for (int i=lcnt;i;i--)
ret=max(ret,tmp+rsum[lis[i]]),tmp+=sum[lis[i]];
return ret;
}
int RQ(int x,int L,int R){
lcnt=0;
divi(x,1,n,L,R);
int tmp=0,ret=0;
for (int i=1;i<=lcnt;i++)
ret=max(ret,tmp+lsum[lis[i]]),tmp+=sum[lis[i]];
return ret;
}
int _a,_b,_c,_d;
inline int Check(int x)
{
int ret=0;
ret+=Sum(ed[x],1,n,_b,_c);
ret+=LQ(ed[x],_a,_b-1);
ret+=RQ(ed[x],_c+1,_d);
return ret>=0;
}
int lastans=0,q[5];
inline void Solve(){
for (int i=1;i<=4;i++) read(q[i]);
for (int i=1;i<=4;i++) (q[i]+=lastans)%=n;
sort(q+1,q+4+1);
_a=q[1]+1,_b=q[2]+1,_c=q[3]+1,_d=q[4]+1;
int L=1,R=icnt+1,MID;
while (L+1<R)
if (Check(MID=(L+R)>>1))
L=MID;
else
R=MID;
printf("%d\n",lastans=sx[L]);
}
int main()
{
int Q;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n);
for (int i=1;i<=n;i++) read(a[i]),sx[++icnt]=a[i];
sort(sx+1,sx+icnt+1); icnt=unique(sx+1,sx+icnt+1)-sx-1;
for (int i=1;i<=n;i++) a[i]=Bin(a[i]),temp[i]=abcd(a[i],i);
sort(temp+1,temp+n+1);
Build(root[1],1,n,1);
int pnt=1;
ed[1]=root[1]; rcnt=1;
for (int i=1;i<=icnt;i++)
{
while (pnt<=n && temp[pnt].x==i)
rcnt++,Modify(root[rcnt],root[rcnt-1],1,n,temp[pnt].y,-1),pnt++;
ed[i+1]=root[rcnt];
}
read(Q);
while (Q--) Solve();
return 0;
}