普通平衡树的基础操作

Posted knightero

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了普通平衡树的基础操作相关的知识,希望对你有一定的参考价值。

技术图片

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

普通平衡树的常规操作模板

普通平衡树可以实现求排名这样的问题,输入很多同学的成绩,求89分排在多少位,或者第几位是多少名

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

main函数

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 struct opt { int num, value; };
 6 struct Segtree { int value; };
 7 opt Data[100010];
 8 Segtree segtree[400010];
 9 vector<int>vt;
10 const int INF = 2147483647;
11 int index;
 1 int main()
 2 {
 3     ios::sync_with_stdio(false);
 4     cin.tie(0);
 5     int n;
 6     cin >> n;
 7     for (int i = 0; i < n; i++)
 8     {
 9         cin >> Data[i].num >> Data[i].value;
10         if (Data[i].num !=4)
//只有4操作是输入排名,而像5和6这样子的操作输入的x可能不在原排列内,即成绩有70 85,现在我要求80的前驱,所以要给80留个位子
//3操作比如成绩有70 85,我想知道如果我成绩80能排多少名,所以也要给80留个位置,不过80的value为0,不影响
11 { 12 vt.push_back(Data[i].value); 13 } 14 } 15 discretization(); 16 for (int i = 0; i < n; i++) 17 { 18 if (Data[i].num == 1) Tree_insert(1, 1, index, get_pos(Data[i].value), 1);//get_pos是为了找到离散化后映射的那个数 19 else if (Data[i].num == 2) Tree_insert(1, 1, index, get_pos(Data[i].value), -1); 20 else if (Data[i].num == 3) cout << Get_ranked(1, 1, index, get_pos(Data[i].value)) << endl; 21 else if (Data[i].num == 4) cout << Get_kth(1, 1, index, Data[i].value) << endl; 22 else if (Data[i].num == 5) cout << Get_pre(Data[i].value) << endl; 23 else if (Data[i].num == 6)cout << Get_succeed(Data[i].value) << endl; 24 } 25 return 0; 26 }

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

离散化

离散化的目的是为了找出对应值来减少空间

比如输入的四个数为10 500 1000 1000000000

没有必要在10-1000000000之中找,而是让1对应10,2对应500,3对应1000,4对应1000000000这样

1 void discretization()
2 {
3     vt.push_back(-INF);//为了让vector中所要操作的数从1开始而不是0开始,先加入一个最小值
4     sort(vt.begin(), vt.end());
5     vt.erase(unique(vt.begin(), vt.end()), vt.end());
//unique能把vector里相同的数提到后面,并返回不重复的排序最后的位置,我们把这个位置到vector末尾的都清掉
//即把那些重复的都清掉,只留一个
6 index = vt.size() - 1;//一共有几个不相同的数 7 return; 8 }

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

求离散化之后的值

1 int get_pos(int value)//为了得到这个数在vector里排第几,利用该数的位置求
2 {
3     return lower_bound(vt.begin(), vt.end(), value)-vt.begin();返回这个值的第一个数的位置再减去开头的(可能有很多重复的,如有四个2,取第一个2)
4 }

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

插入和删除

 1 void Tree_insert(int root, int left, int right, int pos, int k)//一般k只取正负1,表示同样的数有几个,插入就k=1,删除就k=-1
 2 {
 3     if (left == right) {
 4         segtree[root].value += k; return;//到了最底层,找到叶子结点,就可以加或减1了
 5     }
 6     int mid = (left + right) >> 1;//利用二分法找要插入的点的位置
 7     if (pos <= mid) Tree_insert(root << 1, left, mid, pos, k);//要插入的数在mid的左侧
 8     else Tree_insert(root << 1 | 1, mid + 1, right, pos, k);
 9     segtree[root].value = segtree[root << 1].value + segtree[root << 1 | 1].value;//递归更新树
10     return;
11 }

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 查询x数的排名(即成绩为x,排多少)

 

1 int Get_ranked(int root, int left, int right, int pos)
2 {
3     if (left == right) return 1;//返回1是因为题目要求要算入自己
4     int mid = (left + right) >> 1;
5     if (pos <= mid) return Get_ranked(root << 1, left, mid, pos);
6     return segtree[root << 1].value + Get_ranked(root << 1 | 1, mid + 1, right, pos);//左侧的排名也要加上
7 }

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

查询排名为k的数的值

 

1 int Get_kth(int root, int left, int right, int k)//在left和right中找排名为k的值
2 {
3     if (left == right) return vt[left];//注意left是离散化对应的值,要返回它原来离散化之前的值
4         int mid = (left + right) >> 1;
5     if (k <= segtree[root << 1].value) return Get_kth(root << 1, left, mid, k);
6     return Get_kth(root << 1 | 1, mid + 1, right, k-segtree[root<<1].value);//比如要在1-7找排名为6的数,那么就只要在5-7里找排名为2的数
7 }

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

求前驱的值

1 int Get_pre(int k)
2 {
3     return Get_kth(1, 1, index, Get_ranked(1, 1, index, get_pos(k))-1);//先求出所给值的排名,那么他的排名-1就是前驱值的排名,再根据排名求原值
4 }

---------------------------------------------------------   -----------------------------------------------------------------------------------------------------------------------------

求后继的值

1 int Get_succeed(int k)
2 {
3     return Get_kth(1, 1, index, Get_ranked(1, 1, index, get_pos(k+1)));
4 }

---------------------------------------------------------  ------------------------------------------------------------------------------------------------------------------------------

完整代码

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 struct opt { int num, value; };
 6 struct Segtree { int value; };
 7 opt Data[100010];
 8 Segtree segtree[400010];
 9 vector<int>vt;
10 const int INF = 2147483647;
11 int index;
12 void discretization()
13 {
14     vt.push_back(-INF);
15     sort(vt.begin(), vt.end());
16     vt.erase(unique(vt.begin(), vt.end()), vt.end());
17      index = vt.size() - 1;
18     return;
19 }
20 int get_pos(int value)
21 {
22     return lower_bound(vt.begin(), vt.end(), value)-vt.begin();
23 }
24 void Tree_insert(int root, int left, int right, int pos, int k)
25 {
26     if (left == right) {
27         segtree[root].value += k; return;
28     }
29     int mid = (left + right) >> 1;
30     if (pos <= mid) Tree_insert(root << 1, left, mid, pos, k);
31     else Tree_insert(root << 1 | 1, mid + 1, right, pos, k);
32     segtree[root].value = segtree[root << 1].value + segtree[root << 1 | 1].value;
33     return;
34 }
35 int Get_ranked(int root, int left, int right, int pos)
36 {
37     if (left == right) return 1;
38     int mid = (left + right) >> 1;
39     if (pos <= mid) return Get_ranked(root << 1, left, mid, pos);
40     return segtree[root << 1].value + Get_ranked(root << 1 | 1, mid + 1, right, pos);
41 }
42 int Get_kth(int root, int left, int right, int k)
43 {
44     if (left == right) return vt[left];
45         int mid = (left + right) >> 1;
46     if (k <= segtree[root << 1].value) return Get_kth(root << 1, left, mid, k);
47     return Get_kth(root << 1 | 1, mid + 1, right, k-segtree[root<<1].value);
48 }
49 int Get_pre(int k)
50 {
51     return Get_kth(1, 1, index, Get_ranked(1, 1, index, get_pos(k))-1);
52 }
53 int Get_succeed(int k)
54 {
55     return Get_kth(1, 1, index, Get_ranked(1, 1, index, get_pos(k+1)));
56 }
57 int main()
58 {
59     ios::sync_with_stdio(false);
60     cin.tie(0);
61     int n;
62     cin >> n;
63     for (int i = 0; i < n; i++)
64     {
65         cin >> Data[i].num >> Data[i].value;
66         if (Data[i].num !=4)
67         {
68             vt.push_back(Data[i].value);
69         }
70     }
71     discretization();
72     for (int i = 0; i < n; i++)
73     {
74         if (Data[i].num == 1) Tree_insert(1, 1, index, get_pos(Data[i].value), 1);
75         else if (Data[i].num == 2) Tree_insert(1, 1, index, get_pos(Data[i].value), -1);
76         else if (Data[i].num == 3) cout << Get_ranked(1, 1, index, get_pos(Data[i].value)) << endl;
77         else if (Data[i].num == 4) cout << Get_kth(1, 1, index, Data[i].value) << endl;
78         else if (Data[i].num == 5) cout << Get_pre(Data[i].value) << endl;
79         else if (Data[i].num == 6)cout << Get_succeed(Data[i].value) << endl;
80     }
81     return 0;
82 }

 

以上是关于普通平衡树的基础操作的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3224 普通平衡树 平衡树的两种姿势:SBT,splay

bzoj3224Tyvj 1728 普通平衡树 平衡树的三种姿势 :splay,Treap,ScapeGoat_Tree

平衡二叉树的定义及基本操作(查找插入删除)及代码实现

普通平衡树

算法学习:伸展树(splay)

普通平衡树(分块版)