[BZOJ2653]middle(二分+主席树)
2653: middle
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 2252 Solved: 1252
[Submit][Status][Discuss]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
Sample Output
HINT
0:n,Q<=100
1,...,5:n<=2000
0,...,19:n<=20000,Q<=25000
Source
[Submit][Status][Discuss]
关于中位数的题一般首先二分答案,然后根据大于此数和小于此数的个数判断,这题中如果大于等于此数的数-小于此数的数得到的结果大于0则说明中位数可能更大。
换句话说就是所有大于等于的位置赋为1,小于赋为-1,则一段区间和非负。
但是每次二分都要全部赋值一次吗?不需要,因为考虑每相邻的两个权值从1变到-1的数是不多的,用主席树先全部建好就可以了。
需要同时维护三个值:lmax,rmax,sum,发现合并lmax和rmax的时候需要sum,那么这个复杂度还能保证吗?答案是肯定的,因为最多每个点的常数*2,复杂度是不会变的。当然也可以每次将三个点放在一起合并,复杂度不变。
最后,这题第一行的排序是指从小到大排序的。
1 #include<cstdio> 2 #include<algorithm> 3 #define lson ls[x],L,mid 4 #define rson rs[x],mid+1,R 5 #define rep(i,l,r) for (int i=l; i<=r; i++) 6 using namespace std; 7 8 const int N=5000100; 9 struct P{ 10 int sm,lmx,rmx; P(){}; 11 P(int _sm,int _lmx,int _rmx):sm(_sm),lmx(_lmx),rmx(_rmx){} 12 }seg[N]; 13 int ls[N],rs[N],T[30010],q[4],ans,nd,n,Q; 14 struct A{ 15 int x,y; 16 bool operator <(const A &a)const{ return (x==a.x) ? y<a.y : x<a.x; } 17 }a[30010]; 18 19 P operator +(const P &a,const P &b){ return P(a.sm+b.sm,max(a.lmx,a.sm+b.lmx),max(b.rmx,b.sm+a.rmx)); } 20 21 void build(int &x,int L,int R){ 22 x=++nd; 23 if (L==R){ seg[x]=P(1,1,1); return; } 24 int mid=(L+R)>>1; build(lson); build(rson); 25 seg[x]=seg[ls[x]]+seg[rs[x]]; 26 } 27 28 void mdf(int y,int &x,int L,int R,int pos){ 29 x=++nd; ls[x]=ls[y]; rs[x]=rs[y]; 30 if (L==R){ seg[x]=P(-1,-1,-1); return; } 31 int mid=(L+R)>>1; 32 if (pos<=mid) mdf(ls[y],lson,pos); else mdf(rs[y],rson,pos); 33 seg[x]=seg[ls[x]]+seg[rs[x]]; 34 } 35 36 P ask(int x,int L,int R,int l,int r){ 37 if (l>r) return P(0,0,0); 38 if (L==l && r==R) return seg[x]; 39 int mid=(L+R)>>1; 40 if (r<=mid) return ask(lson,l,r); 41 else if (l>mid) return ask(rson,l,r); 42 else return ask(lson,l,mid)+ask(rson,mid+1,r); 43 } 44 45 int jud(int k){ return ask(T[k],1,n,q[0],q[1]).rmx+ask(T[k],1,n,q[1]+1,q[2]-1).sm+ask(T[k],1,n,q[2],q[3]).lmx>=0; } 46 47 int main(){ 48 freopen("bzoj2653.in","r",stdin); 49 freopen("bzoj2653.out","w",stdout); 50 scanf("%d",&n); 51 rep(i,1,n) scanf("%d",&a[a[i].y=i].x); 52 sort(a+1,a+n+1); build(T[1],1,n); 53 rep(i,2,n) mdf(T[i-1],T[i],1,n,a[i-1].y); 54 scanf("%d",&Q); 55 while (Q--){ 56 scanf("%d%d%d%d",&q[0],&q[1],&q[2],&q[3]); 57 q[0]=(q[0]+ans)%n+1; q[1]=(q[1]+ans)%n+1; 58 q[2]=(q[2]+ans)%n+1; q[3]=(q[3]+ans)%n+1; sort(q,q+4); 59 int L=1,R=n; 60 while (L<=R){ 61 int mid=(L+R)>>1; 62 if (jud(mid)) L=mid+1; else R=mid-1; 63 } 64 printf("%d\n",ans=a[L-1].x); 65 } 66 return 0; 67 }