首页 > 其他分享 >treap树

treap树

时间:2023-06-03 13:46:58浏览次数:30  
标签:node int void son treap root size

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

相关文章

  • Treap树学习笔记
    等我写完。普通fhqtreap:enum{Maxn=1000005};structFHQTreap{intlson[Maxn],rson[Maxn],data[Maxn];intrnd[Maxn],sze[Maxn],root,tot,seed;FHQTreap(void){Ms(lson,0),Ms(rson,0),Ms(data,0);Ms(rnd,0),......
  • FHQ_Treap 板子
    namespaceFHQ{#definesiz(x)({Node*_a_=x;_a_==np?0:_a_->sz;})structNode{ Node*ls,*rs; charval;intpri; intsz; voidupdsz(){ sz=1+siz(ls)+siz(rs); }}cs[N];voidoutput(Node*root){ if(root==np)return; output(root-......
  • Treap 学习笔记
    一、TreapTreap是一种通过旋转操作维护性质的二叉搜索树。定义详见要维护的东西还是一样,对于每个节点,要维护它的左右儿子,子树大小,还有权值和随机的优先级(这样才能保证树的高度是\(O(\logn)\)级别的)。注意:旋转、分裂、伸展什么的都是手段,维持平衡树的2个性质才是目的。......
  • 「学习笔记」重修 FHQ-treap
    无旋treap的操作方式使得它天生支持维护序列、可持久化等特性。无旋treap又称分裂合并treap。它仅有两种核心操作,即为分裂与合并。通过这两种操作,在很多情况下可以比旋转treap更方便的实现别的操作。变量与宏定义#definelsch[u][0]#definersch[u][1]intcnt,r......
  • 「学习笔记」平衡树基础:Splay 和 Treap
    「学习笔记」平衡树基础:Splay和Treap点击查看目录目录「学习笔记」平衡树基础:Splay和Treap知识点平衡树概述Splay旋转操作Splay操作插入\(x\)查询排名为\(k\)......
  • 非旋treap
    非旋treap基本操作简述\(FHQ\)\(treap\)借用了\(treap\)的特点,基于\(split\)和\(merge\)操作实现,因其不用旋转,又叫非旋\(treap\),优点是好理解,上手快,代码短(ps:重点是......
  • treap
    \(treap\)基本操作简述\(treap\)将二叉搜索树和堆结合在一起为维护深度,给每个节点随机分配权值\(dat\),如下structtree{ints[2],vl,dt,ct,sz;}t[N];ilvoidupd(cs......
  • 【学习笔记】FHQ Treap
    \(\textbf{I.基本操作}\)\(\textbf{维护子树大小/size_up()}\)和线段树中的\(\text{push_up}\)操作类似,目的是维护以一个节点为根的子树的节点个数。inlinevoids......
  • FHQ-Treap 学习笔记
    FHQ-Treap学习笔记Treap=Tree+Heap.Treap是一种弱平衡二叉树,可以看作是笛卡尔树:其每个点有一个二元组\((Key,Value)\),\(Key\)满足二叉搜索树的性质,而\(Value\)......
  • fhq_treap
    FHQtreap参考:链接Treap:优点:码量小好写核心代码是复读机好理解支持操作多缺点:常数大了点维护平衡的奇怪操作:Treap:旋转FHQTreap:分裂合并节点信......