【BZOJ 2653】middle 主席樹好題推薦
阿新 • • 發佈:2019-01-24
談談這一道題的最強烈的感受在於,我的主席樹入門是經典題目區間第k大樹查詢(當然,因為poj上不會強制線上,還用樹套樹和整體二分寫過那道題),因此,對於主席樹的理解僅僅是一個區間歷史版本維護的理解,即類似於樹套樹的外層區間樹內層全值樹。但是忽略了主席樹的真正偉大之處在於可持久化,而可持久化的也能是權值。
對於這一道題,由於我們不知道中位數是多少,因此考慮二分,而關鍵之處在於如何二分cheak,可以這樣,把所有大於這個數的數定義為1,而小於這個數的定義為-1,那麼只要一段區間區間和大於等於0就說明當前值是可行的,繼續二分,關鍵就在於如何快速得到一段區間的最大和。最簡單的思想是對於每一次的詢問,我On的一次處理,把比他大的賦值為1,小的賦值為-1,然後可以利用線段樹維護區間最大和得到,然後進一步思考,發現每一次都On賦值肯定受不老,那麼思考樹套樹,對於沒一個權值(離散化後)都建立一個區間樹,這個樹就儲存每一個位置是-1,還是1,但是還是受不了,不夠思想已經很接近了,我們繼續觀察可以發現,其實每一個權值對於上一個權值來說的相對狀態只有一個數不同,我們先按權值排序,然後主席樹的每一個葉子節點都是1(對於最小的數來說其他數都比他大),然後不斷插入更大取值的節點,不斷更新這個主席樹,最後就得到一個類似於外層權值樹內層區間樹的主席樹,不過充分利用了先前的資訊,這就是可持久化操作的美妙之處了把。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define maxn 20020 #define ll nod[u].ls #define rr nod[u].rs #define lc nod[u].ls,l,mid #define rc nod[u].rs,mid+1,r using namespace std; int n,a[maxn],b[maxn],tot,rt[maxn]; struct node{int s,ml,mr,ls,rs;}nod[20020*50]; bool cmp(const int& x,const int& y){return a[x]<a[y];} void push_up(int u){ nod[u].s=nod[ll].s+nod[rr].s; nod[u].ml=max(nod[ll].ml,nod[ll].s+nod[rr].ml); nod[u].mr=max(nod[rr].mr,nod[ll].mr+nod[rr].s); } void build(int& u,int l,int r){ u=++tot;nod[u].s=nod[u].ml=nod[u].mr=r-l+1; if(l==r)return; int mid=l+r>>1; build(nod[u].ls,l,mid);build(nod[u].rs,mid+1,r); } void update(int x,int& y, int l,int r,int v){ y=++tot;nod[y].ls=nod[x].ls,nod[y].rs=nod[x].rs; if(l==r){nod[y].ml=nod[y].mr=nod[y].s=-1;return;} int mid=l+r>>1; if(v>mid)update(nod[x].rs,nod[y].rs,mid+1,r,v); else update(nod[x].ls,nod[y].ls,l,mid,v); push_up(y); } int query_sum(int u,int l,int r,int x,int y){ if(l>=x&&r<=y)return nod[u].s; int mid=l+r>>1; if(x>mid)return query_sum(rc,x,y); else if(y<=mid)return query_sum(lc,x,y); else return query_sum(lc,x,y)+query_sum(rc,x,y); } int query_ml(int u,int l,int r,int x,int y){ if(l>=x&&r<=y)return nod[u].ml; int mid=l+r>>1; if(x>mid)return query_ml(rc,x,y); else if(y<=mid)return query_ml(lc,x,y); else return max(query_ml(lc,x,y),query_sum(lc,x,y)+query_ml(rc,x,y)); } int query_mr(int u,int l,int r,int x,int y){ if(x<=l&&r<=y)return nod[u].mr; int mid=l+r>>1; if(x>mid)return query_mr(rc,x,y); else if(y<=mid)return query_mr(lc,x,y); else return max(query_mr(rc,x,y),query_sum(rc,x,y)+query_mr(lc,x,y)); } int Q,c[5],last,l1,l2,r1,r2; bool check(int x){ int ans=query_mr(rt[x],1,n,l1,r1)+query_ml(rt[x],1,n,l2,r2); if(l2>r1+1)ans+=query_sum(rt[x],1,n,r1+1,l2-1); return ans>=0; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",a+i),b[i]=i; sort(b+1,b+1+n,cmp);build(rt[0],1,n); for(int i=1;i<=n;i++)update(rt[i-1],rt[i],1,n,b[i]); scanf("%d",&Q); while(Q--){ for(int i=1;i<=4;i++)scanf("%d",c+i),c[i]=(c[i]+last)%n; sort(c+1,c+5);l1=c[1]+1,r1=c[2]+1,l2=c[3]+1,r2=c[4]+1; int l=1,r=n,ans; while(l<r){ int mid=l+r>>1; if(check(mid))l=mid+1; else r=mid; } printf("%d\n",last=a[b[l]]); } return 0; }