1. 程式人生 > >[模板] 普通平衡樹

[模板] 普通平衡樹

傳送門

您需要一種資料結構:

  • 插入一個數\(x\)
  • 刪除一個數\(x\)
  • 查詢\(x\)這個數在所有數中的排名
  • 查詢排名為\(x\)的數
  • \(x\)這個數的前驅(前驅定義為小於\(x\)的最大數)‘
  • \(x\)這個數的後繼(後繼定義為大於\(x\)的最小數)

平衡樹

  • 不會

樹狀陣列

  • 不會

線段樹

  • 不會
  • 先離散化一下,因為數字太大了
  • 線段樹維護區間內有多少個數
  • 離散化的新編號就是線段樹對應區間的位置

插入ins()

  • 計算\(x\)離散化後的對應編號\(num\)
  • 單點修改區間\([num,num]\)
    ,+1即可

刪除del()

  • 計算\(x\)離散化後的對應編號\(num\)
  • 單點修改區間\([num,num]\),-1即可

查詢排名clac_rk()

  • 計算\(x\)離散化後的對應編號\(num\)
  • 查詢區間\([1,num]\)的和,+1即是答案,因為\(x\)前面有若干個數,若干個數+1就\(x\)的排名

查詢對應排名的數find_rk()

  • 二分查詢,判斷\([1,mid]\)的和與給定排名的大小關係。

查前驅

  • find_rk(calc_rk(x)-1)

查後繼

  • find_rk(calc_rk(x)+N+1),其中\(N\)
    \(x\)的數量

程式碼

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 100005
#define lson (rt<<1)
#define rson (rt<<1|1)

int seg[MAXN<<2];
inline void pushup(int rt) {
    seg[rt] = seg[lson] + seg[rson];
}

void update(int C,int L,int rt,int l,int r) {
    if(l==r&&l==L) {
        seg[rt] += C;
        return;
    }
    int mid = (l+r)>>1;
    if(L<=mid) update(C,L,lson,l,mid);
    else update(C,L,rson,mid+1,r);
    pushup(rt);
}

int query(int L,int R,int rt,int l,int r) {
    if(L>R) return 0;
    if(L<=l&&R>=r) return seg[rt];
    if(L>r||R<l) return 0;
    int mid = (l+r)>>1,ans = 0;
    if(L<=mid) ans += query(L,R,lson,l,mid);
    if(R>mid) ans += query(L,R,rson,mid+1,r);
    return ans;
}

struct Discretization {
    int temp[MAXN],num[MAXN],tot,cnt;
    void reset() {
        tot = 0;
        cnt = 0;
    }
    int get_num(int u) {
        int l = 1, r = tot;
        while(l<r) {
            int mid = (l+r+1)>>1;
            if(num[mid]>u) r = mid - 1;
            else l = mid;
        }
        return l;
    }
    int find(int rk) {
        int l = 1,r = tot;
        while(l<r) {
            int mid = (l+r)>>1;
            int x = query(1,mid,1,1,tot);
            if(x>=rk) r = mid;
            else l = mid + 1;
        }
        return num[l];
    }
    void add(int u) {
        temp[++cnt] = u;
    }
    void unique() {
        for(int i=1;i<=cnt;++i) {
            if(temp[i]!=temp[i+1]) num[++tot] = temp[i];
        }
    }
}D;

struct Opt {
    int opt,num;
}G[MAXN];

int N;

int main() {

    D.reset();

    scanf("%d",&N);
    for(int i=1;i<=N;++i) {
        scanf("%d%d",&G[i].opt,&G[i].num);
        if(G[i].opt!=4) D.add(G[i].num);
    }

    std::sort(D.temp+1,D.temp+1+D.cnt);
    D.unique();

    std::memset(seg,0,sizeof(seg));
    for(int i=1;i<=N;++i) {
        if(G[i].opt==1) update(1,D.get_num(G[i].num),1,1,D.tot);
        else if(G[i].opt==2) update(-1,D.get_num(G[i].num),1,1,D.tot);
        else if(G[i].opt==3) printf("%d\n",query(1,D.get_num(G[i].num)-1,1,1,D.tot) + 1);
        else if(G[i].opt==4) printf("%d\n",D.find(G[i].num));
        else if(G[i].opt==5) {
            int rk = query(1,D.get_num(G[i].num)-1,1,1,D.tot);
            printf("%d\n",D.find(rk));
        }
        else if(G[i].opt==6) {
            int x = D.get_num(G[i].num);
            int rk = query(1,x-1,1,1,D.tot) + query(x,x,1,1,D.tot) + 1;
            printf("%d\n",D.find(rk));
        }
    }

    return 0;
}