Treap实现山寨set

treap插入、删除、查询时间复杂度均为O(logn)

treap树中每个节点有两种权值:键值和该节点优先值

如果只看优先值,这棵树又是一个堆

treap有两种平衡方法:左旋&右旋

insert 插入

remove 删除

_find 查找

kth 返回root为根的树中第k大的元素

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <ctime>
  5 #include <cstdio>
  6 using namespace std;
  7
  8 struct Node
  9 {
 10     Node* ch[2];
 11     int r,v,s;    //r:随机优先级,v:值,s:以本节点为根的子树的结点总数
 12     bool operator < (const Node& rhs)
 13     {
 14         return (r<rhs.r);
 15     }
 16     int cmp(int x)
 17     {
 18         if (x==v) return -1;
 19         return x<v?0:1;
 20     }
 21     void maintain()
 22     {
 23         s=1;
 24         if (ch[0]!=NULL) s+=ch[0]->s;
 25         if (ch[1]!=NULL) s+=ch[1]->s;
 26     }
 27     Node (int v):v(v)        //结构体的构造函数
 28     {
 29         ch[0]=ch[1]=NULL;
 30         r=rand();
 31         s=1;
 32     }
 33 };
 34
 35 void rotate(Node* &o,int d)
 36 {
 37     Node* k=o->ch[d^1];
 38     o->ch[d^1]=k->ch[d];
 39     k->ch[d]=o;
 40     o->maintain();
 41     k->maintain();
 42     o=k;
 43 }
 44
 45 void insert(Node* &o,int x)
 46 {
 47     if (o==NULL)
 48         o=new Node(x);
 49     else
 50     {
 51         //int d=o->cmp(x);        //不用cmp
 52         int d=(x < o->v ? 0 : 1);
 53         insert(o->ch[d],x);
 54         if (o->ch[d]->r > o->r)
 55             rotate(o,d^1);
 56     }
 57     o->maintain();
 58 }
 59
 60 void remove(Node* &o,int x)
 61 {
 62     int d=o->cmp(x);
 63     if (d==-1)
 64     {
 65         Node *u=o;
 66         if ((o->ch[0]!=NULL) && (o->ch[1]!=NULL))
 67         {
 68             int d2=(o->ch[0]->r > o->ch[1]->r ? 1 : 0);
 69             rotate(o,d2);
 70             remove(o->ch[d2],x);
 71         }
 72         else
 73         {
 74             if (o->ch[0]==NULL)
 75                 o=o->ch[1];
 76             else
 77                 o=o->ch[0];
 78             delete u;
 79         }
 80     }
 81     else
 82         remove(o->ch[d],x);
 83     if (o!=NULL)
 84         o->maintain();
 85 }
 86
 87 int kth(Node* o,int k)
 88 {
 89     if ((o==NULL)||(k<=0)||(k > o->s))
 90         return 0;
 91     int s=(o->ch[1]==NULL ? 0 : o->ch[1]->s);
 92     if (k==s+1)
 93         return o->v;
 94     else if (k<=s)
 95         return kth(o->ch[1],k);
 96     else
 97         return kth(o->ch[0],k-s-1);
 98
 99 }
100
101 int _find(Node* o,int x)
102 {
103     while (o!=NULL)
104     {
105         int d=o->cmp(x);
106         if (d==-1)
107             return 1;
108         else
109             o=o->ch[d];
110     }
111     return 0;
112 }
113
114 int main()
115 {
116     //freopen("in.txt","r",stdin);
117
118     int n,m,opr,x;
119     srand(time(0));
120     cin>>n;
121     Node* root=new Node(0);
122     for (int i=1;i<=n;i++)
123     {
124         cin>>opr>>x;
125         if (opr==1)
126         {
127             insert(root,x);
128         }
129         else if (opr==2)
130         {
131             if (!_find(root,x))
132                 cout<<"Not Found,Operation Failed"<<endl;
133             else
134                 remove(root,x);
135         }
136     }
137     cout<<"-----------------"<<endl;
138     cin>>m;
139     for (int i=1;i<=m;i++)
140     {
141         cin>>x;
142         if (_find(root,x))
143             cout<<"Found"<<endl;
144         else
145             cout<<"Not Found"<<endl;
146     }
147     cout<<"-----------------"<<endl;
148     cin>>m;
149     for (int i=1;i<=m;i++)
150     {
151         cin>>x;
152         int ans=kth(root,x);
153         cout<<x<<"th: "<<ans<<endl;
154     }
155 }

PS:发现一个画图论图形的神器:GraphViz

时间: 2024-08-07 06:02:49

Treap实现山寨set的相关文章

Treap

先推荐一篇文章和黄学长的代码http://hzwer.com/1712.html    https://wenku.baidu.com/view/c8c11e1e650e52ea55189887.html 黄学长的代码既不用指针又很短,真心推荐 Treap,顾名思义,Tree+Heap,它既满足二叉搜索树的性质,又满足堆的性质 对于二叉搜索树,如果我们把数有序加入,那么它的时间效率会退化成O(n). 我们引入一个随机数(即下文描述的修正值),使得随机数满足堆的性质(小根堆或大根堆,不一定要是完全

【贪心+Treap】BZOJ1691-[Usaco2007 Dec]挑剔的美食家

[题目大意] 有n头奶牛m种牧草,每种牧草有它的价格和鲜嫩度.每头奶牛要求它的牧草的鲜嫩度要不低于一个值,价格也不低于一个值.每种牧草只会被一头牛选择.问最少要多少钱? [思路] 显然的贪心,把奶牛和牧草都按照鲜嫩度由大到小排序,对于每奶牛把鲜嫩度大于它的都扔进treap,然后找出后继. 不过注意后继的概念是大于它且最小的,然而我们这里是可以等于的,所以应该是找cow[i].fresh-1的后继,注意一下…… 1 #include<iostream> 2 #include<cstdio&

1503: [NOI2004]郁闷的出纳员 Treap

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 6263  Solved: 2190[Submit][Status] Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,如果心情不好,就可

数组splay ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) #include <cstdio> #define Max 100005 #define Inline __attri\ bute__( ( optimize( "-O2" ) ) ) Inline void read (int &now) { now = 0; register char word = getchar (); bool temp = false; while (wor

平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板【超详解】

平衡树初阶——AVL平衡二叉查找树 一.什么是二叉树 1. 什么是树. 计算机科学里面的树本质是一个树状图.树首先是一个有向无环图,由根节点指向子结点.但是不严格的说,我们也研究无向树.所谓无向树就是将有向树的所有边看成无向边形成的树状图.树是一种递归的数据结构,所以我们研究树也是按照递归的方式去研究的. 2.什么是二叉树. 我们给出二叉树的递归定义如下: (1)空树是一个二叉树. (2)单个节点是一个二叉树. (3)如果一棵树中,以它的左右子节点为根形成的子树都是二叉树,那么这棵树本身也是二叉

【bzoj3224】Tyvj 1728 普通平衡树 平衡树的三种姿势 :splay,Treap,ScapeGoat_Tree

直接上代码 正所谓 人傻自带大常数 平衡树的几种姿势:  AVL Red&Black_Tree 码量爆炸,不常用:SBT 出于各种原因,不常用. 常用: Treap 旋转 基于旋转操作和随机数堆 但不支持区间操作. 非旋转 基于随机数堆和拆分合并操作 常数较大 Spaly 完全基于旋转 各种操作 ScapeGoat_Tree 基于a权值平衡树和压扁重构 无旋转 但不支持区间操作 PS:非旋转可以实现平衡树的可持久化,从而来套一些东西 splay #include<cstdio> #de

利用CEF山寨一个翻译器

起因 在某些情况下,有将从某种类型的语言翻译成另一种类型语言的需求.比如在生成实体时,可能需要将中文名称转换成英文.于是利用CEFSharp山寨了一个翻译器.效果图如下: CEF简介 CEF全称为Chromium Emmbed Framework,是一个开源项目.用于嵌入基于 Google Chromium 项目的 Web 浏览器控件. CEF在.NET中的应用 CEF是由C++所写,无法直接应用到.NET中.需要通过某种形式进行包装.常见的有Xilium.CefGlue和CEFSharp.我个

Treap标准模板

这是Treap的模板程序,支持Left/Right Rotate,Find the maxnum/minnum,Find the predecessor/successor of a node,Add/Delete nodes 等绝大多数功能(不包含类似于"查找排名第k的元素"这样奇怪的东西的代码) #include<bits/stdc++.h> #include<windows.h> #define maxn 1000001 #define Random(x)

[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作 第二行有n个数,表示有序序列 下面有m行,opt表示操作标号 若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间