1. 1 void lt(int &k){
  2. 2 int tmp = t[k].r;
  3. 3 t[k].r = t[tmp].l;
  4. 4 t[tmp].l = k;
  5. 5 t[tmp].size = t[k].size;
  6. 6 t[k].size = t[t[k].l].size + t[t[k].r].size + t[k].cnt;
  7. 7 k = tmp;
  8. 8 }
  1. 1 void rt(int &k){
  2. 2 int tmp = t[k].l;
  3. 3 t[k].l = t[tmp].r;
  4. 4 t[tmp].r = k;
  5. 5 t[tmp].size = t[k].size;
  6. 6 t[k].size = t[t[k].r].size + t[t[k].l].size + t[k].cnt;
  7. 7 k = tmp;
  8. 8 }
  1. 1 void Insert(int &k,int num){
  2. 2 if(!k){//如果这是一个没有被创建过的新的节点就创建一个新的节点
  3. 3 k = ++size;
  4. 4 t[k].wt = rand();//为该新节点赋予一个随机值weight
  5. 5 t[k].val = num;//为该节点赋予一个数值大小value
  6. 6 t[k].cnt = t[k].size = 1;
  7. 7 return ;
  8. 8 }
  9. 9 ++t[k].size;//插入了一个新节点,所以路径上每个结点的子树大小++
  10. 10 if(num == t[k].val){//如果这个数值被添加到树中过,就把那个节点处的cnt++
  11. 11 ++t[k].cnt;
  12. 12 return ;
  13. 13 }
  14. 14 if(num < t[k].val){//如果要被插入的数值比当前结点数值小,向左子树寻找
  15. 15 Insert(t[k].l,num);
  16. 16 if(t[t[k].l].wt < t[k].wt)//如果左右孩子其中一个不满足最小堆,即其中一个小于父亲节点,则通过旋转使其满足最小堆
  17. 17 rt(k);
  18. 18 }
  19. 19 else{//如果要被插入的数值比当前结点数值大,向右子树寻找
  20. 20 Insert(t[k].r,num);
  21. 21 if(t[t[k].r].wt < t[k].wt)//维护最小堆
  22. 22 lt(k);
  23. 23 }
  1. 1 void Delete(int &k,int num){
  2. 2 if(!k)
  3. 3 return ;
  4. 4 if(t[k].val == num){
  5. 5 if(t[k].cnt > 1){//如果某个数值被插入2次及以上,在节点处cnt--即可。
  6. 6 --t[k].cnt;
  7. 7 --t[k].size;
  8. 8 return ;
  9. 9 }
  10. 10 else if(!(t[k].l * t[k].r)){//如果那个数值只被插入了一次且左右孩子至少有一个为空,则直接把不为空的孩子接到父亲节点上。
  11. 11 k = t[k].l + t[k].r;
  12. 12 return ;
  13. 13 }
  14. 14 else{//如果两个孩子都不为空,则把两个孩子中weight较小的旋转到父亲节点,把原来的要删除的节点一直旋转成叶子节点或只有一个非空孩子的节点。
  15. 15 if(t[t[k].l].wt <= t[t[k].r].wt){
  16. 16 rt(k);
  17. 17 Delete(k,num);
  18. 18 }
  19. 19 else{
  20. 20 lt(k);
  21. 21 Delete(k,num);
  22. 22 }
  23. 23 }
  24. 24 }
  25. 25 else{
  26. 26 --t[k].size;//经过的路径size全都--
  27. 27 if(num < t[k].val)//判断接下来寻找num位置的走向
  28. 28 Delete(t[k].l,num);
  29. 29 else
  30. 30 Delete(t[k].r,num);
  31. 31 }
  32. 32 }
  1. 1 int Rank(int &k,int num){
  2. 2 if(!k)
  3. 3 return 0;
  4. 4 if(t[k].val == num)
  5. 5 return t[t[k].l].size + 1;//若与当前结点相等,左节点size+1就是排名,防止t[k].cnt影响排名
  6. 6 else if(t[k].val > num)
  7. 7 return Rank(t[k].l,num);
  8. 8 else
  9. 9 return Rank(t[k].r,num) + t[t[k].l].size + t[k].cnt;//递归到右子树返回的是在右子树之内的排名,要加上父节点的cnt和左孩子的size
  10. 10 }
  1. 1 int Search(int &k,int num){
  2. 2 if(!k)
  3. 3 return 0;
  4. 4 if(num <= t[t[k].l].size)
  5. 5 return Search(t[k].l,num);
  6. 6 else if(num <= t[t[k].l].size + t[k].cnt)//如果排名属于(左孩子size,左孩子size + 当前结点cnt]区间内,则第k大数就是该节点的数值大小。
  7. 7 return t[k].val;
  8. 8 else
  9. 9 return Search(t[k].r,num - t[t[k].l].size - t[k].cnt);//进行右子树的递归,排名需剪掉左子树的size和当前结点cnt,这样才能保证在右子树找到正确结果。
  10. 10 }
  1. 1 int Pre(int &k,int num){
  2. 2 if(!k)
  3. 3 return -2147483648;//返回极小值避免对下方max函数产生影响
  4. 4 if(t[k].val >= num)
  5. 5 return Pre(t[k].l,num);
  6. 6 else
  7. 7 return max(t[k].val,Pre(t[k].r,num));//如果当前结点数值小于num,则在该节点右子树寻找比该节点数值更大的节点,后序同理
  8. 8 }
  9. 9 int Nex(int &k,int num){
  10. 10 if(!k)
  11. 11 return 2147483647;
  12. 12 if(t[k].val <= num)
  13. 13 return Nex(t[k].r,num);
  14. 14 else
  15. 15 return min(t[k].val,Nex(t[k].l,num));
  16. 16 }

版权声明:本文为reddest原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/reddest/p/9884998.html