1. 程式人生 > >【BZOJ 2653】middle 主席樹好題推薦

【BZOJ 2653】middle 主席樹好題推薦

談談這一道題的最強烈的感受在於,我的主席樹入門是經典題目區間第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;
}