普通平衡树的基础操作
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