正题
题目链接:https://www.luogu.com.cn/problem/P2839
题目大意
nnn个数字,mmm次询问给出(a,b,c,d)(a,b,c,d)(a,b,c,d)表示左端点在[a,b][a,b][a,b]中,右端点在[c,d][c,d][c,d]的子区间中中位数最大的值。
解题思路
显然我们需要二分一下答案midmidmid,然后我们要选择一个满足条件的子区间使得区间≥mid\geq mid≥mid的个数减去<mid<mid<mid的个数最大。
换一种主席树的方式,我们里面是一个按照区间的线段树,外面是按照值域分的。然后维护区间最大前缀和和最大后缀和即可。
时间复杂度O(nlog2n)O(n\log^2 n)O(nlog2n)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=21000,M=N<<4;
struct node{int pre,suf,num;
};
int n,m,tot,a[N],b[N],q[4],rt[N];
int ls[M],rs[M],pre[M],suf[M],num[M];
vector<int> v[N];
void PushUp(int x,int L,int R){int mid=(L+R)>>1;if(!ls[x])ls[x]=++tot,pre[tot]=suf[tot]=-1,num[tot]=-(mid-L+1);if(!rs[x])rs[x]=++tot,pre[tot]=suf[tot]=-1,num[tot]=-(R-mid);pre[x]=max(pre[ls[x]],num[ls[x]]+pre[rs[x]]);suf[x]=max(suf[rs[x]],num[rs[x]]+suf[ls[x]]);num[x]=num[ls[x]]+num[rs[x]];return;
}
int Change(int x,int L,int R,int pos){int now=++tot;if(L==R){pre[now]=suf[now]=num[now]=1;return now;}int mid=(L+R)>>1;if(pos<=mid)ls[now]=Change(ls[x],L,mid,pos),rs[now]=rs[x];else rs[now]=Change(rs[x],mid+1,R,pos),ls[now]=ls[x];PushUp(now,L,R);return now;
}
node Ask(int x,int L,int R,int l,int r){if(l>r||!x)return (node){-1,-1,-(r-l+1)};int mid=(L+R)>>1;if(L==l&&R==r)return (node){pre[x],suf[x],num[x]};if(r<=mid)return Ask(ls[x],L,mid,l,r);if(l>mid)return Ask(rs[x],mid+1,R,l,r);node la=Ask(ls[x],L,mid,l,mid);node ra=Ask(rs[x],mid+1,R,mid+1,r);return (node){max(la.pre,la.num+ra.pre),max(ra.suf,ra.num+la.suf),la.num+ra.num};
}
bool check(int x,int a,int b,int c,int d){node L=Ask(rt[x],1,n,a,b);node M=Ask(rt[x],1,n,b+1,c-1);node R=Ask(rt[x],1,n,c,d);return (L.suf+M.num+R.pre)>=0;
}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];sort(b+1,b+1+n);int cnt=unique(b+1,b+1+n)-b-1;for(int i=1;i<=n;i++){a[i]=lower_bound(b+1,b+1+cnt,a[i])-b;v[a[i]].push_back(i);}for(int i=cnt;i>=1;i--){rt[i]=Change(rt[i+1],1,n,v[i][0]);for(int j=1;j<v[i].size();j++)rt[i]=Change(rt[i],1,n,v[i][j]);}scanf("%d",&m);int last=0;for(int i=1;i<=m;i++){scanf("%d%d%d%d",&q[1],&q[2],&q[3],&q[0]);q[1]=(q[1]+last)%n+1;q[2]=(q[2]+last)%n+1;q[3]=(q[3]+last)%n+1;q[0]=(q[0]+last)%n+1;sort(q,q+4);int l=1,r=cnt;while(l<=r){int mid=(l+r)>>1;if(check(mid,q[0],q[1],q[2],q[3]))l=mid+1;else r=mid-1;}printf("%d\n",last=b[r]);}return 0;
}