P3369 【模板】普通平衡樹
阿新 • • 發佈:2021-08-17
【模板】普通平衡樹
題目描述
您需要寫一種資料結構(可參考題目標題),來維護一些數,其中需要提供以下操作: 1. 插入 $x$ 數 2. 刪除 $x$ 數(若有多個相同的數,因只刪除一個) 3. 查詢 $x$ 數的排名(排名定義為比當前數小的數的個數 $+1$ ) 4. 查詢排名為 $x$ 的數 5. 求 $x$ 的前驅(前驅定義為小於 $x$,且最大的數) 6. 求 $x$ 的後繼(後繼定義為大於 $x$,且最小的數)輸入輸出格式
輸入格式
第一行為 $n$,表示操作的個數,下面 $n$ 行每行有兩個數 $\text{opt}$ 和 $x$,$\text{opt}$ 表示操作的序號( $ 1 \leq \text{opt} \leq 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\le n \le 10^5$,$|x| \le 10^7$FHQ(分裂式Treap)實現
#include <bits/stdc++.h> using namespace std; #define getsize(x) (x ? x -> size : 0) #define ll long long const int MAXN = 1e5 + 10; class FHQ { public : class Node { public : int key, rank; int size; Node *ls, *rs; void push_up() { size = getsize(ls) + getsize(rs) + 1; } }pool[2 * MAXN], *rt; int top; //分裂 p 返回 p 的左子p_l, 右子p_r void split(Node *p , Node *&p_l, Node *&p_r, int x)//分裂當前子樹 { if(!p)//p 為空,無需分離 { p_l = p_r = NULL; return ; } if(p -> key <= x)//如果 p 的值比 x 小,就把 p 接到左子上,繼續分裂 p 的右子 { p_l = p; split(p -> rs, p_l -> rs, p_r, x); p_l -> push_up(); } else//否則分 p 的左子 { p_r = p; split(p -> ls, p_l ,p_r -> ls, x); p_r -> push_up(); } } void merge(Node *&p, Node *p_l, Node *p_r) { if(!p_l || !p_r)//如果有一為空 { p = p_l ? p_l : p_r; return ; } if(p_l -> rank < p_r -> rank)//維護平衡 { p = p_l; merge(p -> rs, p_l -> rs, p_r); } else { p = p_r; merge(p -> ls, p_l, p_r -> ls); } p -> push_up(); } Node *newNode(int x) { Node *p = pool + (++top); p -> key = x; p -> rank = rand(); p -> size = 1; return p; } void insert(Node *&rt, int x) { Node *p1, *p2; split(rt, p1, p2 ,x - 1); merge(rt, p1 ,newNode(x)); merge(rt, rt, p2); } void remove(Node *&rt, int x) { Node *p1, *p2, *p3 , *p4; split(rt, p1 ,p2 ,x - 1); split(p2, p3 ,p4, x); merge(p3, p3 -> ls, p3 -> rs); merge(p3, p3, p4); merge(rt, p1, p3); } int getRank(Node *&rt, int x) { Node *p1 ,*p2; split(rt, p1 ,p2, x - 1); int ans = getsize(p1); merge(rt, p1 ,p2); return ans; } int getKey(Node *p, int rank) { while(p) { if(rank <= getsize(p -> ls)) p = p -> ls; else if(rank > getsize(p -> ls) + 1) { rank -= getsize(p -> ls) + 1; p = p -> rs; } else return p -> key; } return 0; } int lower(Node *p, int x) { int ans = INT_MIN; while(p) { if(x > p -> key) { ans = max(ans, p -> key); p = p -> rs; } else p = p -> ls; } return ans; } int upper(Node *p, int x) { int ans = INT_MAX; while(p) { if(x < p -> key) { ans = min(ans, p -> key); p = p -> ls; } else p = p -> rs; } return ans; } }FHQ; int t; int op, x; int main() { scanf("%d", &t); while(t--) { scanf("%d %d", &op, &x); if(op == 1) { FHQ.insert(FHQ.rt, x); } if(op == 2) { FHQ.remove(FHQ.rt, x); } if(op == 3) { printf("%d\n", FHQ.getRank(FHQ.rt, x) + 1); } if(op == 4) { printf("%d\n", FHQ.getKey(FHQ.rt, x)); } if(op == 5) { printf("%d\n" , FHQ.lower(FHQ.rt, x)); } if(op == 6) { printf("%d\n", FHQ.upper(FHQ.rt, x)); } } return 0; }