Treap树 = tree+heap
数和堆的集合,每个节点有值val,也有优先级key,那么这棵树的形态就被确定了,和插入顺序无关了(有赖于优先级
避免退化成链:再生成节点时,随机生成优先级,然后插入时动态调整
1、FHQ treap又称无旋treap,没有旋转操作,使用分裂和合并两个操作维护树的平衡
struct node{ int l,r; int val; int key; int size; }tr[N]; int root,idx; int newnode(int v){ } void pushup(){ //向上更新 } void split(int p,int v,int &x,int &y){ //分裂操作 注意在递归的过程中,连接了分裂后的新边 } int merg(int x,int y){ //合并,根据key的大小,注意在递归的过程中,连接了分裂后的新边 } void inser(int v){ //插入节点,先分裂,再合并,连续两次合并 } void del(int v){ //删除操作,先分裂、再合并 } int get_k(int p,int k){ //返回第k个节点 } void get_pre(int v){ //找前驱 } void get_suc(int v){ //找后继 } void get_rank(int v){//排名 } void get_val(int k){//数值 }
删除:如果有两个子节点,找到优先级大的,把x向反方向旋转,也就是把x向树的下层调整,直到旋转到叶子节点
!很多题目涉及名次树
常用操作:
struct node,旋转rotate,插入insert(),查找第k大的数kth(),查询某个数find()【名次树】
少林 hdu 4585
#include <bits/stdc++.h> using namespace std; using ll = long long; const ll inf = 4e18+10; const int mod = 1000000007; const int mx = 5e6+5; //check the limits, dummy typedef pair<int, int> pa; const double PI = acos(-1); ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } #define swa(a,b) a^=b^=a^=b #define re(i,a,b) for(int i=(a),_=(b);i<_;i++) #define rb(i,a,b) for(int i=(b),_=(a);i>=_;i--) #define clr(a) memset(a, 0, sizeof(a)) #define lowbit(x) ((x)&(x-1)) #define mkp make_pair void sc(int& x) { scanf("%d", &x); }void sc(int64_t& x) { scanf("%lld", &x); }void sc(double& x) { scanf("%lf", &x); }void sc(char& x) { scanf(" %c", &x); }void sc(char* x) { scanf("%s", x); } int m, n,k,sum=0,ans=0,t; int id[mx]; struct node { int size;//以这个节点为根的子树的节点总数,用于名次树 int rank;//优先级 int key;//键值 node *son[2];//son[0]左儿子,son[1]右儿子 bool operator<(const node& a)const { return rank < a.rank;} int cmp(int x)const { if (x == key)return -1; return x < key ? 0 : 1; } void update() { size = 1; if (son[0] != NULL)size += son[0]->size; if (son[1] != NULL)size += son[1]->size; } }; void rotate(node* &o, int d) {//d=0,左旋,d=1,右旋 node *k = o->son[d ^ 1];//d^1等价于1-d,但是更快 o->son[d ^ 1] = k->son[d]; k->son[d] = o; o->update(); k->update(); o = k; } void insert(node* &o, int x) {//把x插入树中 if (o == NULL) { o = new node(); o->son[0] = o->son[1] = NULL; o->rank = rand(); o->key = x; o->size = 1; } else { int d = o->cmp(x); insert(o->son[d],x); o->update(); if (o < o->son[d]); rotate(o, d ^ 1); } } int kth(node* o, int k) {//返回第k大的数 if (o == NULL || k <= 0 || k > o->size) return -1; int s = o->son[1] == NULL ? 0 : o->son[1]->size; if (k == s + 1)return o->key; else if (k <= s)return kth(o->son[1], k); else return kth(o->son[0], k - s - 1); } int find(node* o, int k) {//返回元素k的名次 if (o == NULL) return -1; int d = o->cmp(k); if (d == -1) return o->son[1] == NULL ? 1 : o->son[1]->size + 1; else if (d == 1)return find(o->son[d],k); else { int tmp = find(o->son[d], k); if (tmp == -1) return -1; else { return o->son[1] == NULL ? tmp + 1 : tmp + 1 + o ->son[1]->size; } } } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); while (cin>>n&&n) { srand(time(NULL)); int k, g; cin >> k >> g; node* root = new node(); root->son[0] = root-> son[1] = NULL; root->rank = rand(); root->key = g; root->size = 1; id[g] = k; cout << k << ' ' << 1<<endl; re(i, 2, n + 1) { cin >> k >> g; id[g] = k; insert(root, g); t = find(root, g);//返回新和尚的名次 int ans1, ans2; ans1 = kth(root, t - 1);//前一名的老和尚 ans2 = kth(root, t + 1);//后一名的老和尚 if (ans1 != -1 && ans2 != -1) { ans = ans1 - g >= g - ans2 ? ans2 : ans1; } else if (ans1 == -1) ans = ans2; else ans = ans1; cout << k << ' ' << id[ans] << endl; } } return 0; }
标签:node,int,void,son,treap,root,size From: https://www.cnblogs.com/shirlybaby/p/17453863.html