bzoj2653: middle
題意:給n個(gè)數(shù),每次詢(xún)問(wèn)a,b,c,d,你要選定一個(gè)區(qū)間使得該區(qū)間中位數(shù)最大,其中a,b為區(qū)間左端點(diǎn)可選范圍,c,d同理。
OTZ陳老師出的神題。
先考慮一個(gè)簡(jiǎn)單問(wèn)題:只有一個(gè)詢(xún)問(wèn)的情況。此時(shí)我們二分中位數(shù),并且將區(qū)間內(nèi)小中位數(shù)的數(shù)標(biāo)為-1,大于的標(biāo)為1,此時(shí)區(qū)間最大和如果大等0,則說(shuō)明中位數(shù)可以變大,然后二分下去就可以了。
加上詢(xún)問(wèn)之后,我們就要維護(hù)這樣一個(gè)區(qū)間最大和了。考慮主席樹(shù),我們對(duì)于每一個(gè)值,建出它對(duì)應(yīng)的1,-1樹(shù),然后二分,到對(duì)應(yīng)的樹(shù)上去求最大區(qū)間和就好了。那么問(wèn)題來(lái)了,怎么維護(hù)這樣一個(gè)最大區(qū)間和呢?首先,我們有必選區(qū)間b,c所以我要把這個(gè)區(qū)間的和算上,對(duì)于可選區(qū)間a,b-1和c+1,d,我們要求一個(gè)最大前后綴和。這個(gè)東西可以這樣求(以前綴和為例):max(左兒子sum+右兒子前綴,左兒子前綴)。
那么整體思路出來(lái)了:先建出一棵全線段樹(shù)(全為1),然后我們把原序列排個(gè)序(要把下標(biāo)對(duì)應(yīng)好),然后一個(gè)一個(gè)按順序丟進(jìn)樹(shù)里,把小等自己的變?yōu)?1,以供這個(gè)數(shù)的后一個(gè)數(shù)查詢(xún)時(shí)使用。 然后我們二分答案,對(duì)于當(dāng)前答案去樹(shù)上找最大區(qū)間和,如果大等0則滿足條件。
這道題主席樹(shù)建出來(lái),第一維度是權(quán)值,第二維度是下標(biāo)。我一開(kāi)始想的一二唯獨(dú)是反的,而大神說(shuō)這樣有問(wèn)題,一直沒(méi)想通哪里有問(wèn)題。。。再去和大神討論一下。
寫(xiě)這道題寫(xiě)得異常艱難。先是在想二分會(huì)不會(huì)有問(wèn)題(實(shí)際是不會(huì)的,因?yàn)轭}目弄出來(lái)的中位數(shù)在偶數(shù)個(gè)時(shí)會(huì)選擇較大的那個(gè))昨天晚上寫(xiě)了第一版,有點(diǎn)問(wèn)題,第二天寫(xiě)了第二版,還是有問(wèn)題,什么沒(méi)有排序?qū)е聸](méi)有正確性啊,建樹(shù)不分配編號(hào)啊什么的。然后各種改,終于過(guò)了(感謝ihopenot大佬)。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 20005 4 #define M 400005 5 #define CT Chairman_Tree 6 int n,Q,p[5],ans; 7 struct data{ 8 int num,pos; 9 bool operator < (const data& w)const{ 10 if(num==w.num) return pos<w.pos; 11 return num<w.num; 12 } 13 }a[N]; 14 namespace Chairman_Tree{ 15 struct node{ 16 int son[2],sum,ls,rs; 17 }tr[M]; 18 int sz,root[N]; 19 void build(int& x,int l,int r){ 20 x=++sz; 21 tr[x].ls=tr[x].rs=tr[x].sum=r-l+1; 22 if(l==r) return; 23 int mid=(l+r)>>1; 24 build(tr[x].son[0],l,mid); 25 build(tr[x].son[1],mid+1,r); 26 } 27 void insert(int x,int& y,int l,int r,int lim){ 28 tr[y=++sz].sum=tr[x].sum-2; 29 if(l==r){ 30 tr[y].ls=tr[y].rs=0; 31 return; 32 } 33 memcpy(tr[y].son,tr[x].son,sizeof(tr[y].son)); 34 int mid=(l+r)>>1,LS,RS; 35 if(lim>mid) insert(tr[x].son[1],tr[y].son[1],mid+1,r,lim); 36 else insert(tr[x].son[0],tr[y].son[0],l,mid,lim); 37 LS=tr[y].son[0],RS=tr[y].son[1]; 38 tr[y].ls=max(tr[LS].sum+tr[RS].ls,tr[LS].ls); 39 tr[y].rs=max(tr[RS].sum+tr[LS].rs,tr[RS].rs); 40 } 41 inline void insert(int i) {insert(root[i],root[i+1],1,n,a[i].pos);} 42 int query(int x,int L,int R,int l,int r){ 43 if(L==l && R==r) return tr[x].sum; 44 int mid=(L+R)>>1; 45 if(r<=mid) return query(tr[x].son[0],L,mid,l,r); 46 else if(mid<l) return query(tr[x].son[1],mid+1,R,l,r); 47 else return query(tr[x].son[0],L,mid,l,mid)+query(tr[x].son[1],mid+1,R,mid+1,r); 48 } 49 int lquery(int x,int L,int R,int l,int r){ 50 if(L==l && R==r) return tr[x].ls; 51 int mid=(L+R)>>1; 52 if(r<=mid) return lquery(tr[x].son[0],L,mid,l,r); 53 else if(mid<l) return lquery(tr[x].son[1],mid+1,R,l,r); 54 else { 55 int t1=query(tr[x].son[0],L,mid,l,mid)+lquery(tr[x].son[1],mid+1,R,mid+1,r),t2=lquery(tr[x].son[0],L,mid,l,mid); 56 return max(t1,t2); 57 } 58 } 59 int rquery(int x,int L,int R,int l,int r){ 60 if(L==l && R==r) return tr[x].rs; 61 int mid=(L+R)>>1; 62 if(r<=mid) return rquery(tr[x].son[0],L,mid,l,r); 63 else if(mid<l) return rquery(tr[x].son[1],mid+1,R,l,r); 64 else { 65 int t1=rquery(tr[x].son[0],L,mid,l,mid)+query(tr[x].son[1],mid+1,R,mid+1,r),t2=rquery(tr[x].son[1],mid+1,R,mid+1,r); 66 return max(t1,t2); 67 } 68 } 69 } 70 using namespace CT; 71 inline int read(){ 72 int x=0,f=1; char a=getchar(); 73 while(a<'0' || a>'9') {if(a=='-') f=-1; a=getchar();} 74 while(a>='0' && a<='9') x=x*10+a-'0',a=getchar(); 75 return x*f; 76 } 77 inline bool jud(int x){ 78 return rquery(root[x],1,n,p[1],p[2]-1)+query(root[x],1,n,p[2],p[3])+lquery(root[x],1,n,p[3]+1,p[4])>=0; 79 } 80 int main(){ 81 n=read(); 82 for(int i=1;i<=n;i++) a[i]=(data){read(),i}; 83 build(root[1],1,n); 84 sort(a+1,a+1+n); 85 for(int i=1;i<n;i++) insert(i); 86 Q=read(); 87 while(Q--){ 88 int l=1,r=n; 89 for(int i=1;i<=4;i++) p[i]=(read()+ans)%n+1; 90 sort(p+1,p+5); 91 while(l<r){ 92 int mid=(l+r+1)>>1; 93 if(jud(mid)) l=mid; 94 else r=mid-1; 95 } 96 ans=a[l].num; printf("%d\n",ans); 97 } 98 return 0; 99 }?
轉(zhuǎn)載于:https://www.cnblogs.com/enigma-aw/p/6202920.html
總結(jié)
以上是生活随笔為你收集整理的bzoj2653: middle的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 返回顶部按钮的制作
- 下一篇: hash_hmac函数使用不当造成的安全