版權聲明:本文爲博主原創文章,未經博主容許不得轉載。php
bzoj 2653node
題意:ios
一個長度爲n的序列a,設其排過序以後爲b,其中位數定義爲b[n/2],其中a,b從0開始標號,除法取下整。數組
給你一個長度爲n的序列s。優化
回答Q個這樣的詢問:s的左端點在[a,b]之間,右端點在[c,d]之間的子序列中,最大的中位數。spa
其中a<b<c<d。code
位置也從0開始標號。blog
強制在線。get
解法:string
首先能夠想到的是二分答案,再判斷是否知足條件 。
對於答案x,咱們將原數組中大於等於x的數記1,小於的記爲-1,那麼一個區間是否知足中位數大於等於x的條件就是區間和大於等於0 。
求解子段用線段樹就能夠快速作到,跟網上的主流作法不一樣,我線段樹節點記錄的是區間最大最小前綴和,查詢的話只需詢問區間[c,d]的最大前綴和 和 [a-1,b-1]的最小前綴和,二者一減就是最大的區間和,再判斷它是否大於等於0 。這樣子好寫,並且效率更高 。(雖然不知道爲何,估計是優化到常數上了,當時是跑了940MS,排到了十三名,以前都沒一題排這麼前過 。。。)
固然不可能對每個答案x都創建一顆線段樹,這時就要用到主席樹,按不一樣的答案x建樹 。以後隨意搞搞就能夠了 _(:з」∠)_
code
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #include <cstring> 6 #include <queue> 7 #include <set> 8 #include <vector> 9 #include <map> 10 #define LL long long 11 12 using namespace std; 13 14 const int N=20000+7; 15 16 int Ls[N*30],Rs[N*30],dc[N*30],mm[N*30][2]; // 0 最小值 1 最大值 17 int root[N],tot=0; 18 19 struct node{ 20 int id,key; 21 bool operator < (const node &t) const { 22 return key<t.key; 23 } 24 }a[N]; 25 int sorted[N]; 26 int n; 27 28 inline bool scan_d(int &num) { 29 char in;bool IsN=false; 30 in=getchar(); 31 if(in==EOF) return false; 32 while(in!='-'&&(in<'0'||in>'9')) in=getchar(); 33 if(in=='-'){ IsN=true;num=0;} 34 else num=in-'0'; 35 while(in=getchar(),in>='0'&&in<='9'){ 36 num*=10,num+=in-'0'; 37 } 38 if(IsN) num=-num; 39 return true; 40 } 41 42 inline void pushup(int k){ 43 mm[k][0]=min(mm[Ls[k]][0],mm[Rs[k]][0])-dc[k]; 44 mm[k][1]=max(mm[Ls[k]][1],mm[Rs[k]][1])-dc[k]; 45 } 46 47 inline int bulidtree(int L,int R){ 48 int k=tot++; 49 dc[k]=0; 50 51 if (L==R){ 52 mm[k][0]=mm[k][1]=L; 53 return k; 54 } 55 56 int mid=(L+R)>>1; 57 Ls[k]=bulidtree(L,mid); 58 Rs[k]=bulidtree(mid+1,R); 59 pushup(k); 60 61 return k; 62 } 63 64 inline void COPY(int x,int y){ 65 dc[x]=dc[y]; 66 mm[x][0]=mm[y][0]; 67 mm[x][1]=mm[y][1]; 68 Ls[x]=Ls[y]; 69 Rs[x]=Rs[y]; 70 } 71 72 inline int update(int o,int x,int y,int L,int R){ 73 int k=tot++; 74 COPY(k,o); 75 if (x==L && y==R){ 76 dc[k]+=2; 77 mm[k][0]-=2; 78 mm[k][1]-=2; 79 return k; 80 } 81 82 int mid=(L+R)>>1; 83 if (y<=mid) Ls[k]=update(Ls[k],x,y,L,mid); 84 else if (x>mid) Rs[k]=update(Rs[k],x,y,mid+1,R); 85 else { 86 Ls[k]=update(Ls[k],x,mid,L,mid); 87 Rs[k]=update(Rs[k],mid+1,y,mid+1,R); 88 } 89 pushup(k); 90 91 return k; 92 } 93 94 inline int query(int o,int x,int y,int L,int R,int op){ 95 if (L==x && R==y) return mm[o][op]; 96 97 int mid=(L+R)>>1; 98 if (y<=mid) return query(Ls[o],x,y,L,mid,op)-dc[o]; 99 else if (x>mid) return query(Rs[o],x,y,mid+1,R,op)-dc[o]; 100 else { 101 if (op==1) return max(query(Ls[o],x,mid,L,mid,op),query(Rs[o],mid+1,y,mid+1,R,op))-dc[o]; 102 else return min(query(Ls[o],x,mid,L,mid,op),query(Rs[o],mid+1,y,mid+1,R,op))-dc[o]; 103 } 104 } 105 106 inline bool ok(int x,int a,int b,int c,int d){ 107 return query(root[x],c,d,0,n,1)-query(root[x],a-1,b-1,0,n,0)>=0; 108 } 109 110 inline int search(int a,int b,int c,int d){ 111 int L=1,R=n; 112 int mid; 113 while (L<=R){ 114 mid=(L+R)>>1; 115 if (ok(mid,a,b,c,d)) L=mid+1; 116 else R=mid-1; 117 } 118 return sorted[R]; 119 } 120 121 int main(){ 122 scan_d(n); 123 for (int i=1;i<=n;i++){ 124 scan_d(a[i].key); 125 sorted[i]=a[i].key; 126 a[i].id=i; 127 } 128 sort(sorted+1,sorted+n+1); 129 sort(a+1,a+n+1); 130 131 root[0]=bulidtree(0,n); 132 int j=1; 133 for (int i=1;i<=n;i++){ 134 root[i]=root[i-1]; 135 while (j<=n && a[j].key<sorted[i]){ 136 root[i]=update(root[i],a[j].id,n,0,n); 137 j++; 138 } 139 } 140 141 int m,q[4],ans=0; 142 scan_d(m); 143 while (m--){ 144 for (int i=0;i<4;i++){ 145 scan_d(q[i]); 146 q[i]=(q[i]%n+ans%n)%n+1; 147 } 148 sort(q,q+4); 149 printf("%d\n",ans=search(q[0],q[1],q[2],q[3])); 150 } 151 return 0; 152 }