1. 程式人生 > >[BZOJ2653]middle 主席樹+二分

[BZOJ2653]middle 主席樹+二分

time 前綴 hid com har sum algorithm isdigit solved

2653: middle

Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 2042 Solved: 1123
[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

我們二分中位數,對於大於mid的數賦值為1,小於mid的數為-1。若最大的區間和大於0則可行。

考慮建一顆主席樹(維護權值線段樹),root[i]為中位數為i時的前綴樹。

二分查詢即可。

技術分享圖片
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<algorithm>
 7 #define maxn 20005
 8 #define ls(i) t[i].s[0]
 9 #define rs(i) t[i].s[1]
10 using namespace std;
11 int read() {
12     int x=0,f=1
;char ch=getchar(); 13 for(;!isdigit(ch);ch=getchar()) if(ch==-) f=-1; 14 for(;isdigit(ch);ch=getchar()) x=x*10+ch-0; 15 return x*f; 16 } 17 struct tmp { 18 int v,id; 19 bool operator <(const tmp tt) const {return v<tt.v;} 20 }a[maxn]; 21 struct data { 22 int lm,rm,sum,s[2]; 23 }t[maxn*20]; 24 int n,q,sz; 25 int root[maxn]; 26 void pushup(int x) { 27 t[x].lm=max(t[ls(x)].lm,t[ls(x)].sum+t[rs(x)].lm); 28 t[x].rm=max(t[rs(x)].rm,t[rs(x)].sum+t[ls(x)].rm); 29 t[x].sum=t[rs(x)].sum+t[ls(x)].sum; 30 } 31 void build(int &rt,int l,int r) { 32 rt=++sz; 33 if(l==r) {t[rt].sum=t[rt].lm=t[rt].rm=1;return;} 34 int mid=l+r>>1; 35 build(ls(rt),l,mid);build(rs(rt),mid+1,r); 36 pushup(rt); 37 38 } 39 void update(int p,int &rt,int l,int r,int x) { 40 rt=++sz; 41 t[rt]=t[p]; 42 if(l==r) {t[rt].sum=-1;t[rt].lm=t[rt].rm=0;return;} 43 int mid=l+r>>1; 44 if(x<=mid) update(ls(p),ls(rt),l,mid,x); 45 else update(rs(p),rs(rt),mid+1,r,x); 46 pushup(rt); 47 } 48 int qs(int rt,int l,int r,int x,int y) { 49 if(x>y) return 0; 50 if(l>=x&&r<=y) return t[rt].sum; 51 int mid=l+r>>1,ans=0; 52 if(x<=mid) ans+=qs(ls(rt),l,mid,x,y); 53 if(y>mid) ans+=qs(rs(rt),mid+1,r,x,y); 54 return ans; 55 } 56 int ql(int rt,int l,int r,int x,int y) { 57 if(x>y) return 0; 58 if(l>=x&&r<=y) return t[rt].lm; 59 int mid=l+r>>1,ans=0; 60 if(x<=mid) ans=max(ql(ls(rt),l,mid,x,y),ans); 61 if(y>mid) ans=max(qs(ls(rt),l,mid,x,mid)+ql(rs(rt),mid+1,r,x,y),ans); 62 return ans; 63 } 64 int qr(int rt,int l,int r,int x,int y) { 65 if(x>y) return 0; 66 if(l>=x&&r<=y) return t[rt].rm; 67 int mid=l+r>>1,ans=0; 68 if(x<=mid) ans=max(qs(rs(rt),mid+1,r,mid+1,y)+qr(ls(rt),l,mid,x,y),ans); 69 if(y>mid) ans=max(qr(rs(rt),mid+1,r,x,y),ans); 70 return ans; 71 } 72 bool check(int x,int q1,int q2,int q3,int q4) { 73 int s=qs(root[x],0,n-1,q2,q3)+ql(root[x],0,n-1,q3+1,q4)+qr(root[x],0,n-1,q1,q2-1); 74 return s>=0; 75 } 76 int main() { 77 t[0].sum=t[0].lm=t[0].rm=0; 78 n=read(); 79 for(int i=0;i<n;i++) a[i].v=read(),a[i].id=i; 80 sort(a,a+n); 81 build(root[0],0,n-1); 82 for(int i=1;i<n;i++) update(root[i-1],root[i],0,n-1,a[i-1].id); 83 int ans=0; 84 q=read(); 85 for(int i=1;i<=q;i++) { 86 int ask[5]; 87 for(int j=1;j<=4;j++) ask[j]=(read()+ans)%n; 88 sort(ask+1,ask+5); 89 int L=0,R=n-1; 90 while(L<=R) { 91 int mid=L+R>>1; 92 if(check(mid,ask[1],ask[2],ask[3],ask[4])) L=mid+1; 93 else R=mid-1; 94 } 95 ans=a[L-1].v; 96 printf("%d\n",ans); 97 } 98 }
View Code

[BZOJ2653]middle 主席樹+二分