我們一起學程式-五子棋
阿新 • • 發佈:2020-09-04
P3369 【模板】普通平衡樹
題目描述
您需要寫一種資料結構(可參考題目標題),來維護一些數,其中需要提供以下操作:
- 插入 x 數
- 刪除 x 數(若有多個相同的數,因只刪除一個)
- 查詢 x 數的排名(排名定義為比當前數小的數的個數 +1 )
- 查詢排名為 x 的數
- 求 x 的前驅(前驅定義為小於 x,且最大的數)
- 求 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; }