1. 程式人生 > 實用技巧 >我們一起學程式-五子棋

我們一起學程式-五子棋

P3369 【模板】普通平衡樹

題目描述

您需要寫一種資料結構(可參考題目標題),來維護一些數,其中需要提供以下操作:

  1. 插入 x 數
  2. 刪除 x 數(若有多個相同的數,因只刪除一個)
  3. 查詢 x 數的排名(排名定義為比當前數小的數的個數 +1 )
  4. 查詢排名為 x 的數
  5. 求 x 的前驅(前驅定義為小於 x,且最大的數)
  6. 求 x 的後繼(後繼定義為大於 x,且最小的數)

輸入格式

第一行為 n,表示操作的個數,下面 n 行每行有兩個數 opt和 x,opt表示操作的序號( 1≤opt≤6 )

輸出格式

對於操作 3,4,5,6 每行輸出一個數,表示對應答案

輸入輸出樣例

輸入 #1

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

輸出 #1

106465
84185
492737

說明/提示

【資料範圍】
對於 100% 的資料,1≤n≤\(10^5\),∣x∣≤\(10^7\)

\(Splay\)板子:

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 1e5 + 5, inf = 1e9;
int n, tot, root;
struct node { int fa, val, cnt, siz, son[2]; } t[N]; //son[0/1]表示左右兒子

void up(int x) {
    t[x].siz = t[x].cnt + t[t[x].son[0]].siz + t[t[x].son[1]].siz;
}

void rotate(int x) {
    int y = t[x].fa, z = t[y].fa, k = t[y].son[1] == x;
    if(z) t[z].son[t[z].son[1] == y] = x; t[x].fa = z;
    t[y].son[k] = t[x].son[k ^ 1]; t[t[x].son[k ^ 1]].fa = y;
    t[x].son[k ^ 1] = y; t[y].fa = x;
    up(y); up(x);
}

void Splay(int x, int goal) {
    if(goal == 0) root = x;
    while(t[x].fa ^ goal) {
        int y = t[x].fa, z = t[y].fa;
        if(z ^ goal) (t[y].son[1] == x) ^ (t[z].son[1] == y) ? rotate(x) : rotate(y); 
        rotate(x);
    }
}

void Insert(int x) {
    int u = root, Fa = 0;
    while(u && t[u].val ^ x) Fa = u, u = t[u].son[x > t[u].val];
    if(u) t[u].cnt++;
    else {
        u = ++tot;
        if(Fa) t[Fa].son[x > t[Fa].val] = u;
        t[u].val = x; t[u].siz = 1; t[u].cnt = 1;
        t[u].fa = Fa; t[u].son[0] = t[u].son[1] = 0;
    }
    Splay(u, 0);
}

void Find(int x) {
    int u = root;
    if(!u) return ;
    while(t[u].son[x > t[u].val] && t[u].val ^ x) u = t[u].son[x > t[u].val];
    Splay(u, 0);
}

int pre_nxt(int x, bool f) {
    Find(x);
    if(t[root].val < x && !f) return root;
    if(t[root].val > x && f) return root;
    int u = t[root].son[f];
    while(t[u].son[f ^ 1]) u = t[u].son[f ^ 1];
    return u;
}

void Delete(int x) {
    int nxt = pre_nxt(x, 1), pre = pre_nxt(x, 0);
    Splay(pre, 0); Splay(nxt, pre);
    int u = t[nxt].son[0];
    if(--t[u].cnt == 0) t[nxt].son[0] = 0, t[t[nxt].fa].siz--;
    else Splay(u, 0);
}

int Kth(int k) {
    int u = root;
    while(1) {
        if(t[t[u].son[0]].siz + t[u].cnt < k) {
            k -= t[t[u].son[0]].siz + t[u].cnt;
            u = t[u].son[1];
        }
        else if(t[t[u].son[0]].siz >= k) u = t[u].son[0];
        else return t[u].val;
    }
}

int main() {

    n = read();
    Insert(-inf); Insert(inf);
    for(int i = 1, x, opt;i <= n; i++) {
        opt = read(); x = read();
        if(opt == 1) { Insert(x); }
        else if(opt == 2) { Delete(x); }
        else if(opt == 3) { Find(x); printf("%d\n", t[t[root].son[0]].siz); }
        else if(opt == 4) { printf("%d\n", Kth(x + 1)); } //因為插入了-inf,所以要加1
        else printf("%d\n", t[pre_nxt(x, opt == 6)].val);
    }

    return 0;
}