题目描述
一个长度为 $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)mod n,(b+x)mod n,(c+x)mod n,(d+x)mod 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:$
主席树好题。
如果区间和大于等于$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 ",lastans); 102 } 103 return 0; 104 }