2653: middle
Description
一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。
位置也从0开始标号。
我会使用一些方式强制你在线。
Input
第一行序列长度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]。
输入保证满足条件。
Output
Q行依次给出询问的答案。
Sample Input
5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
271451044
271451044
969056313
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
271451044
271451044
969056313
Sample Output
HINT
0:n,Q<=100
1,...,5:n<=2000
0,...,19:n<=20000,Q<=25000
中位数的话就是至少这段区间中有(r-l+1)/2个数比他大,那么我们设答案为M,区间中比M小的数为-1,比M大的数为1,那么这个区间和一定是非负的,
那么对于这道题的询问就变成了询问在左端点和右端点同时满足情况下的最大连续区间子段和,看其是否非负即可,
同时我们会发现,比M大的数都不满足,比M小的数都满足,所以M是具有单调性的,所以可以二分M,
那么我们的问题就在于,如何快速建出对应M的线段树,当我们离散化之后,每次答案加1,对应的都只有1个点的正负需要变化,那么我们就可以建立可持久化线段树,
值1~n对应的n个序列,然后就可做了。
http://dzy493941464.is-programmer.com/posts/40266.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<queue> 10 #include<vector> 11 #include<set> 12 #define inf 1000000000 13 #define maxn 100000+5 14 #define maxm 5000000+5 15 #define eps 1e-10 16 #define ll long long 17 #define mid (l+r>>1) 18 #define for0(i,n) for(int i=0;i<=(n);i++) 19 #define for1(i,n) for(int i=1;i<=(n);i++) 20 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 21 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 22 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 23 using namespace std; 24 int read(){ 25 int x=0,f=1;char ch=getchar(); 26 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 27 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 28 return x*f; 29 } 30 struct seg{ 31 int lx,rx,sum; 32 }t[maxm]; 33 int n,tot,b[5],rt[maxn],ls[maxm],rs[maxm]; 34 pair<int,int> a[maxn]; 35 void build(int &k,int l,int r){ 36 if(!k)k=++tot; 37 t[k]=(seg){r-l+1,r-l+1,r-l+1}; 38 if(l==r)return ; 39 build(ls[k],l,mid);build(rs[k],mid+1,r); 40 } 41 seg operator +(seg l,seg r){ 42 return (seg){max(l.lx,l.sum+r.lx),max(r.rx,r.sum+l.rx),l.sum+r.sum}; 43 } 44 void update(int x,int &y,int l,int r,int z){ 45 y=++tot; 46 if(l==r){ 47 t[y]=(seg){-1,-1,-1}; 48 return ; 49 } 50 ls[y]=ls[x];rs[y]=rs[x]; 51 if(z<=mid)update(ls[x],ls[y],l,mid,z); 52 else update(rs[x],rs[y],mid+1,r,z); 53 t[y]=t[ls[y]]+t[rs[y]]; 54 } 55 seg ask(int k,int l,int r,int x,int y){ 56 if(x>y)return (seg){0,0,0}; 57 if(l==x&&r==y)return t[k]; 58 if(y<=mid)return ask(ls[k],l,mid,x,y); 59 else if(x>mid)return ask(rs[k],mid+1,r,x,y); 60 else return ask(ls[k],l,mid,x,mid)+ask(rs[k],mid+1,r,mid+1,y); 61 } 62 bool check(int x){ 63 return ask(rt[x],1,n,b[1],b[2]).rx+ask(rt[x],1,n,b[2]+1,b[3]-1).sum+ask(rt[x],1,n,b[3],b[4]).lx>=0; 64 } 65 int main(){ 66 //freopen("input.txt","r",stdin); 67 //freopen("output.txt","w",stdout); 68 n=read(); 69 for1(i,n)a[a[i].second=i].first=read(); 70 sort(a+1,a+n+1); 71 build(rt[0],1,n); 72 for1(i,n)update(rt[i-1],rt[i],1,n,a[i].second); 73 int T=read(),ans=0; 74 while(T--){ 75 for1(i,4)b[i]=(read()+ans)%n+1; 76 sort(b+1,b+4+1); 77 int l=1,r=n; 78 while(l<=r) 79 if(check(mid-1))l=mid+1; 80 else r=mid-1; 81 printf("%d\n",ans=a[r].first); 82 } 83 return 0; 84 }