[国家集训队]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)\bmod n,(b+x)\bmod n,(c+x)\bmod n,(d+x)\bmod 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
输出
271451044
271451044
969056313

说明/提示

对于$5\%$的数据, $n,Q \leq 100$

对于另 $25\%$ 的数据,$n \leq 2000$

对于 $100\%$ 的数据, $n \leq 20000$$Q \leq 25000$


$Solution:$

  主席树好题。

  因为是要我们求中位数,所以惯用的套路就是二分一个$mid$,然后大于等于$mid$的看成$1$,小于$mid$的看成$-1$,然后我们求一下区间和, 

如果区间和大于等于$0$的话就说明中位数只能更大,令$l=mid+1$,如果区间和小于$0$的话就令$r=mid-1$,继续二分。

  因为我们要中位数尽可能地大,所以我们要求的区间和尽可能大,但是这道题的区间不确定。经过思考我们发现$[b+1,c-1]$这个区间是必选的,

也就是说这个区间是确定的,所以我们只要让$[a,b]$的右端最大子段和$+$ $[c,d]$的左端最大子段和最大即可。

  这个显然是可以用线段树维护的。

  所以我们得出了一个做法:先把$a[]$排序一下。对于每一个二分出来的$mid$,首先给区间$[a,d]$赋值,然后以区间为下标建立一棵线段树并同时

维护一下每一个区间的区间和,左端最大子段和,右端最大子段和。然后再在$[a,b]$求出它的最大后缀,$[c,d]$中求出它的最大前缀,再加一下$[b+1,c-1]$

这个区间的区间和然后判一下是否大于等于$0$,继续二分。。。

  但是这样空间显然会炸,所以我们还要继续优化。

  我们可以发现对于$mid$来说,如果我们的$mid+1$的话,受到影响的值只有$mid$——从$+1$变成$-1$,所以我们可以用主席树暴力修改该位置上的值就$OK$了。


 

$Code:$

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N=20010;
  4 int n,lmax[N*20],rmax[N*20],lc[N*20],rc[N*20],sum[N*20],rt[N*20],cnt;
  5 void push_down(int p){
  6     sum[p]=sum[lc[p]]+sum[rc[p]];
  7     lmax[p]=max(lmax[lc[p]],sum[lc[p]]+lmax[rc[p]]);
  8     rmax[p]=max(rmax[rc[p]],sum[rc[p]]+rmax[lc[p]]);
  9 }
 10 void copy(int now,int pre){
 11     lc[now]=lc[pre];
 12     rc[now]=rc[pre];
 13     lmax[now]=lmax[pre];
 14     rmax[now]=rmax[pre];
 15     sum[now]=sum[pre];
 16 }
 17 int build(int l,int r){
 18     int p=++cnt;
 19     if(l==r){
 20         lmax[p]=rmax[p]=sum[p]=1;
 21         return p;
 22     }
 23     int mid=(l+r)>>1;
 24     lc[p]=build(l,mid);
 25     rc[p]=build(mid+1,r);
 26     push_down(p);
 27     return p;
 28 }
 29 void ins(int &p,int pre,int l,int r,int x,int val){
 30     p=++cnt;
 31     copy(p,pre);
 32     if(l==r){
 33         lmax[p]=rmax[p]=sum[p]=val;
 34         return;
 35     }
 36     int mid=(l+r)>>1;
 37     if(x<=mid) ins(lc[p],lc[pre],l,mid,x,val);
 38     else ins(rc[p],rc[pre],mid+1,r,x,val);
 39     push_down(p);
 40 }
 41 int query_sum(int p,int l,int r,int L,int R){
 42     int res=0;
 43     if(L<=l&&r<=R)
 44         return sum[p];
 45     int mid=(l+r)>>1;
 46     if(L<=mid) res+=query_sum(lc[p],l,mid,L,R);
 47     if(R>mid) res+=query_sum(rc[p],mid+1,r,L,R);
 48      return res;
 49 }
 50 int query_lsum(int p,int l,int r,int a,int b){
 51     if(a<=l&&r<=b)
 52         return lmax[p];
 53     int mid=(l+r)>>1;
 54     if(b<=mid) return query_lsum(lc[p],l,mid,a,b);
 55     else if(a>=mid+1) return query_lsum(rc[p],mid+1,r,a,b);
 56     else return max(query_sum(lc[p],l,mid,a,mid)+query_lsum(rc[p],mid+1,r,mid+1,b),query_lsum(lc[p],l,mid,a,mid));
 57 }
 58 int query_rsum(int p,int l,int r,int c,int d){
 59     if(c<=l&&r<=d)
 60         return rmax[p];
 61     int mid=(l+r)>>1;
 62     if(d<=mid) return query_rsum(lc[p],l,mid,c,d);
 63     else if(c>=mid+1) return query_rsum(rc[p],mid+1,r,c,d);
 64     else return max(query_rsum(rc[p],mid+1,r,mid+1,d),query_rsum(lc[p],l,mid,c,mid)+query_sum(rc[p],mid+1,r,mid+1,d));
 65 }
 66 bool check(int mid,int a,int b,int c,int d){
 67     int sum=0;
 68     if(b+1<=c-1)
 69         sum+=query_sum(rt[mid],1,n,b+1,c-1);
 70     sum+=query_rsum(rt[mid],1,n,a,b);
 71     sum+=query_lsum(rt[mid],1,n,c,d);
 72     return sum>=0;
 73 }
 74 struct data{
 75     int x,pos;
 76 }a[N];
 77 bool cmp(data a,data b){
 78     return a.x<b.x;
 79 }
 80 int main(){
 81     scanf("%d",&n);
 82     for(int i=1;i<=n;i++) scanf("%d",&a[i].x),a[i].pos=i;
 83     sort(a+1,a+1+n,cmp);
 84     rt[1]=build(1,n);
 85     for(int i=2;i<=n+1;i++)
 86         ins(rt[i],rt[i-1],1,n,a[i-1].pos,-1);
 87     int Q,lastans=0;
 88     scanf("%d",&Q);
 89     while(Q--){
 90         int q[10],id;
 91         scanf("%d%d%d%d",&q[1],&q[2],&q[3],&q[4]);
 92         for(int i=1;i<=4;i++) q[i]=(q[i]+lastans)%n;
 93         sort(q+1,q+1+4);
 94         int l=1,r=n;
 95         while(l<=r){
 96             int mid=(l+r)>>1;
 97             if(check(mid,q[1]+1,q[2]+1,q[3]+1,q[4]+1)) l=mid+1,id=mid;
 98             else r=mid-1;
 99         }
100         lastans=a[id].x;
101         printf("%d\n",lastans);
102     }
103     return 0;
104 }

 

 
posted @ 2021-01-30 14:12  谁伴我流浪  阅读(70)  评论(0编辑  收藏  举报