• 数据结构:Treap


    关于重量平衡树的相关概念可以参考姊妹文章:重量平衡树之替罪羊树

    Treap是依靠旋转来维护平衡的重量平衡树中最为好写的一中,因为它的旋转不是LL就是RR

    对于每一个新的节点,它给这个节点分配了一个随机数,用作优先级,然后以这个优先级来维护一个堆结构

    由于堆本身就是完全二叉树结构,这样维护之后的树就无限接近于完全二叉树,所以还是很神奇的

    这棵树满足BST的一切性质,除了不能处理序列问题之外已经无敌了

    应该说,抛去动态树问题之外,这是实战最好用的树了

    我们还是先看定义:

    struct Tree
    {
        int v,w;
        int size;
        int rnd;
        int ch[2];
    }t[maxn];
    int root;
    int size;
    int ans=0;

    在这里v是值,w是同值的节点个数,size是子树的节点总数,rnd是优先级,外面:root是根节点,size是根节点中元素个数,ans是统计答案用的临时变量

    我们这里还是先介绍插入操作,平衡树问题如果不是处理序列的,建议就一个一个插

    void insert(int &k,int x)
    {
        if(k==0)
        {
            size++;
            k=size;
            t[k].size=t[k].w=1;
            t[k].v=x;
            t[k].rnd=rand();
            return;
        }
        t[k].size++;
        if(t[k].v==x)
            t[k].w++;
        else if(x>t[k].v)
        {
            insert(t[k].ch[1],x);
            if(t[t[k].ch[1]].rnd<t[k].rnd)
                lturn(k);
        }
        else
        {
            insert(t[k].ch[0],x);
            if(t[t[k].ch[0]].rnd<t[k].rnd)
                rturn(k);
        }
    }

    插入时根据是否是叶子节点,遍历到的节点的w值等进行维护

    每次插入要判断一下是否满足堆结构,进行相应的旋转调整

    下面给出旋转调整的函数,基本上可以作为左旋和右旋的模板了

    void rturn(int &k)
    {
        int tmp=t[k].ch[0];
        t[k].ch[0]=t[tmp].ch[1];
        t[tmp].ch[1]=k;
        t[tmp].size=t[k].size;
        update(k);
        k=tmp;
    }
    void lturn(int &k)
    {
        int tmp=t[k].ch[1];
        t[k].ch[1]=t[tmp].ch[0];
        t[tmp].ch[0]=k;
        t[tmp].size=t[k].size;
        update(k);
        k=tmp;
    }

    然后我们给出update函数,这里要维护的东西很少,只有一个size,所以这个时候的update就是更新size用的

    void update(int k)
    {
        t[k].size=t[t[k].ch[0]].size+t[t[k].ch[1]].size+t[k].w;
    }

    然后是四种基本查询工作,各种平衡树基本一致,也可以作为模板记下来了

    int query_rank(int k,int x)
    {
        if(k==0)
            return 0;
        if(t[k].v==x)
            return t[t[k].ch[0]].size+1;
        else if(x>t[k].v)
            return t[t[k].ch[0]].size+t[k].w+query_rank(t[k].ch[1],x);
        else 
            return query_rank(t[k].ch[0],x);
    }
    int query_num(int k,int x)
    {
        if(k==0)
            return 0;
        if(x<=t[t[k].ch[0]].size)
            return query_num(t[k].ch[0],x);
        else if(x>t[t[k].ch[0]].size+t[k].w)
            return query_num(t[k].ch[1],x-t[t[k].ch[0]].size-t[k].w);
        else
            return t[k].v;
    }
    void query_pro(int k,int x)
    {
        if(k==0)
            return;
        if(t[k].v<x)
            ans=k,query_pro(t[k].ch[1],x);
        else
            query_pro(t[k].ch[0],x);
    }
    void query_sub(int k,int x)
    {
        if(k==0)
            return;
        if(t[k].v>x)
            ans=k,query_sub(t[k].ch[0],x);
        else
            query_sub(t[k].ch[1],x);
    }

    最后我们给出完整的模板,这棵树一定要熟练掌握,只要是平衡树问题,很大可能都是用它来完成的

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 using namespace std;
      5 const int maxn=100005;
      6 int n;
      7 struct Tree
      8 {
      9     int v,w;
     10     int size;
     11     int rnd;
     12     int ch[2];
     13 }t[maxn];
     14 int root;
     15 int size;
     16 int ans=0;
     17 void update(int k)
     18 {
     19     t[k].size=t[t[k].ch[0]].size+t[t[k].ch[1]].size+t[k].w;
     20 }
     21 void rturn(int &k)
     22 {
     23     int tmp=t[k].ch[0];
     24     t[k].ch[0]=t[tmp].ch[1];
     25     t[tmp].ch[1]=k;
     26     t[tmp].size=t[k].size;
     27     update(k);
     28     k=tmp;
     29 }
     30 void lturn(int &k)
     31 {
     32     int tmp=t[k].ch[1];
     33     t[k].ch[1]=t[tmp].ch[0];
     34     t[tmp].ch[0]=k;
     35     t[tmp].size=t[k].size;
     36     update(k);
     37     k=tmp;
     38 }
     39 void insert(int &k,int x)
     40 {
     41     if(k==0)
     42     {
     43         size++;
     44         k=size;
     45         t[k].size=t[k].w=1;
     46         t[k].v=x;
     47         t[k].rnd=rand();
     48         return;
     49     }
     50     t[k].size++;
     51     if(t[k].v==x)
     52         t[k].w++;
     53     else if(x>t[k].v)
     54     {
     55         insert(t[k].ch[1],x);
     56         if(t[t[k].ch[1]].rnd<t[k].rnd)
     57             lturn(k);
     58     }
     59     else
     60     {
     61         insert(t[k].ch[0],x);
     62         if(t[t[k].ch[0]].rnd<t[k].rnd)
     63             rturn(k);
     64     }
     65 }
     66 void del(int &k,int x)
     67 {
     68     if(k==0)
     69         return;
     70     if(t[k].v==x)
     71     {
     72         if(t[k].w>1)
     73         {
     74             t[k].w--;
     75             t[k].size--;
     76             return;
     77         }
     78         if(t[k].ch[0]*t[k].ch[1]==0)
     79             k=t[k].ch[0]+t[k].ch[1];
     80         else if(t[t[k].ch[0]].rnd<t[t[k].ch[1]].rnd)
     81             rturn(k),del(k,x);
     82         else
     83             lturn(k),del(k,x);
     84     }
     85     else if(x>t[k].v)
     86         t[k].size--,del(t[k].ch[1],x);
     87     else
     88         t[k].size--,del(t[k].ch[0],x);
     89 }
     90 int query_rank(int k,int x)
     91 {
     92     if(k==0)
     93         return 0;
     94     if(t[k].v==x)
     95         return t[t[k].ch[0]].size+1;
     96     else if(x>t[k].v)
     97         return t[t[k].ch[0]].size+t[k].w+query_rank(t[k].ch[1],x);
     98     else 
     99         return query_rank(t[k].ch[0],x);
    100 }
    101 int query_num(int k,int x)
    102 {
    103     if(k==0)
    104         return 0;
    105     if(x<=t[t[k].ch[0]].size)
    106         return query_num(t[k].ch[0],x);
    107     else if(x>t[t[k].ch[0]].size+t[k].w)
    108         return query_num(t[k].ch[1],x-t[t[k].ch[0]].size-t[k].w);
    109     else
    110         return t[k].v;
    111 }
    112 void query_pro(int k,int x)
    113 {
    114     if(k==0)
    115         return;
    116     if(t[k].v<x)
    117         ans=k,query_pro(t[k].ch[1],x);
    118     else
    119         query_pro(t[k].ch[0],x);
    120 }
    121 void query_sub(int k,int x)
    122 {
    123     if(k==0)
    124         return;
    125     if(t[k].v>x)
    126         ans=k,query_sub(t[k].ch[0],x);
    127     else
    128         query_sub(t[k].ch[1],x);
    129 }
    130 int main()
    131 {
    132     cin>>n;
    133     int tmp,x;
    134     for(int i=1;i<=n;i++)
    135     {
    136         cin>>tmp>>x;
    137         switch(tmp)
    138         {
    139             case 1:insert(root,x);break;
    140             case 2:del(root,x);break;
    141             case 3:cout<<query_rank(root,x)<<endl;break;
    142             case 4:cout<<query_num(root,x)<<endl;break;
    143             case 5:ans=0;query_pro(root,x);cout<<t[ans].v<<endl;break;
    144             case 6:ans=0;query_sub(root,x);cout<<t[ans].v<<endl;break;
    145         }
    146     }
    147     return 0;
    148 }
  • 相关阅读:
    n8n 基于node 的流程自动化工具
    kubectl-trace 基于bpftrace 的kubernetes 集群性能分析工具
    bcc 基于bpf 分析linux 系统性能的强大工具包
    使用arthas 生成火焰图分析jvm
    openjdk11 stretch基础镜像无法找到对应openjdk dbg 包的问题
    async-profiler 容器使用常见问题
    使用jattach 在host 节点查看容器jvm信息
    使用async-profiler简单分析zeebe 工作流引擎的性能
    minio select api 试用
    使用zeebe DebugHttpExporter 查看zeebe 工作流信息
  • 原文地址:https://www.cnblogs.com/aininot260/p/9330967.html
Copyright © 2020-2023  润新知