zoukankan      html  css  js  c++  java
  • [您有新的未分配科技点]可,可,可持久化!?------可持久化平衡树普及版讲解

    今天我们也继续精神满满的可持久化——这次我带来的是可持久化平衡树的讲解。

    可持久化平衡树,顾名思义,和主席树一样支持历史版本的查询。

    可持久化平衡树都可以用什么实现呢?朴素的二叉排序树,或者无旋Treap,或者替罪羊。其他的平衡树都不能实现可持久化

    ……好吧,我们直接把二叉排序树扔掉。下面我们来想一下。

    splay是均摊的log复杂度,这是不清真的

    可能某一次的复杂度很高,就导致复制了很多节点,因此是可以卡的……

    但是换成重量平衡树就没事了。

    我们想一想,重量平衡树:Treap和替罪羊

    替罪羊要拍扁重建,这样之前可持久化的关系会被改变

    有旋的Treap,因为要旋转,更新父子关系也很复杂

    因此只剩下无旋Treap了2333

    我们只需要在进行merge和split操作的时候进行可持久化,复制一下经过的节点即可。

    在具体的代码实现上说,我们只多了一个函数:copy函数,用来复制(好像特意开一个函数不太值……233)

    1 inline void cop(Treap *&a,Treap *b)
    2 {
    3     if(b==null)a=null;
    4     else a=newTreap(0),*a=*b;
    5     //这个函数的关键点有二:一是a要传引用,二是必须写*a=*b。
    6     //*a=*b只把b存储的值赋给了a,而对a的操作不会影响b的值,即实现了可持久化
    7 }

    UPD 感谢rvalue dalao上面的a是传引用……我知识水平不够把这俩弄混了……

    这样,我们只需要在merge和split函数中调用上面的cop函数来复制节点,就可以实现可持久化了。

    更改后的split和merge代码如下

     1 void split(Treap *rt,Treap *&a,Treap *&b,int k)
     2 {
     3     if(!k)cop(b,rt),a=null;
     4     else if(rt->size<=k)cop(a,rt),b=null;
     5     else if(rt->ch[0]->size>=k)
     6         cop(b,rt),split(rt->ch[0],a,b->ch[0],k),b->update();
     7     else cop(a,rt),split(rt->ch[1],a->ch[1],b,k-rt->ch[0]->size-1),a->update();
     8 }
     9 void merge(Treap *&rt,Treap *a,Treap *b)
    10 {
    11     if(a==null)cop(rt,b);
    12     else if(b==null)cop(rt,a);
    13     else if(a->key < b->key)
    14         cop(rt,a),merge(rt->ch[1],a->ch[1],b),rt->update();
    15     else 
    16         cop(rt,b),merge(rt->ch[0],a,b->ch[0]),rt->update();
    17 }

    这样,我们就成功的实现了可持久化:)

    给出一道例题 cogs2314 Persistable Editor http://cogs.pro/cogs/problem/problem.php?pid=2314

    这道题就是在对序列维护实现一个可持久化的平衡树。直接利用无旋Treap实现即可。

    下面给出我的代码:

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <iostream>
      4 #include <ctime>
      5 #include <cstdlib>
      6 using namespace std;
      7 const int N=100005;
      8 int d,cnt;char s[250];
      9 struct Treap
     10 {
     11     Treap *ch[2];
     12     char val;int size,key;
     13     Treap(){val=size=0;key=rand();ch[0]=ch[1]=NULL;}
     14     inline void update(){size=ch[0]->size+ch[1]->size+1;}
     15 }*null=new Treap(),*root[N];
     16 inline Treap* newTreap(char c)
     17 {
     18     Treap *o=new Treap();o->ch[0]=o->ch[1]=null;
     19     o->val=c;o->size=1;return o;
     20 }
     21 inline void cop(Treap *&a,Treap *b)
     22 {
     23     if(b==null)a=null;
     24     else a=newTreap(0),*a=*b;
     25 }
     26 void split(Treap *rt,Treap *&a,Treap *&b,int k)
     27 {
     28     if(!k)cop(b,rt),a=null;
     29     else if(rt->size<=k)cop(a,rt),b=null;
     30     else if(rt->ch[0]->size>=k)
     31         cop(b,rt),split(rt->ch[0],a,b->ch[0],k),b->update();
     32     else cop(a,rt),split(rt->ch[1],a->ch[1],b,k-rt->ch[0]->size-1),a->update();
     33 }
     34 void merge(Treap *&rt,Treap *a,Treap *b)
     35 {
     36     if(a==null)cop(rt,b);
     37     else if(b==null)cop(rt,a);
     38     else if(a->key < b->key)
     39         cop(rt,a),merge(rt->ch[1],a->ch[1],b),rt->update();
     40     else 
     41         cop(rt,b),merge(rt->ch[0],a,b->ch[0]),rt->update();
     42 }
     43 void dfs(Treap *o)
     44 {
     45     if(o==null)return;
     46     dfs(o->ch[0]);
     47     printf("%c",o->val);
     48     if(o->val=='c')d++;
     49     dfs(o->ch[1]);
     50 }
     51 inline void print()
     52 {
     53     int mk,p,x;
     54     scanf("%d%d%d",&mk,&p,&x);mk-=d,p-=d,x-=d;
     55     Treap *a,*b,*c;
     56     split(root[mk],a,b,p-1),split(b,b,c,x);
     57     dfs(b);printf("
    ");
     58     merge(a,a,b),merge(root[mk],a,c);
     59 }
     60 inline Treap* build(char *t)
     61 {
     62     static Treap *stack[210],*x,*last;
     63     int p=0,m=strlen(t);
     64     for(int i=0;i<m;i++)
     65     {
     66         x=newTreap(s[i]);last=null;
     67         while(p&&stack[p]->key > x->key)
     68             {stack[p]->update();last=stack[p];stack[p--]=null;}
     69         if(p)stack[p]->ch[1]=x;
     70         x->ch[0]=last;stack[++p]=x;
     71     }
     72     while(p)stack[p--]->update();
     73     return stack[1];
     74 }
     75 inline void insert()
     76 {
     77     int p;scanf("%d%s",&p,s);p-=d;
     78     Treap *a,*b,*c=build(s);
     79     split(root[cnt],a,b,p);
     80     merge(a,a,c),merge(root[++cnt],a,b);
     81 }
     82 inline void del()
     83 {
     84     int p,x;scanf("%d%d",&p,&x);p-=d,x-=d;
     85     Treap *a,*b,*c;
     86     split(root[cnt],a,b,p-1),split(b,b,c,x);
     87     merge(root[++cnt],a,c);
     88 }
     89 int main()
     90 {
     91     int n,opt;scanf("%d",&n);
     92     null->ch[0]=null->ch[1]=null;
     93     for(int i=0;i<=n;i++)root[i]=null;
     94     while(n--)
     95     {
     96         scanf("%d",&opt);
     97         switch(opt)
     98         {
     99             case 1:insert();break;
    100             case 2:del();break;
    101             case 3:print();break;
    102         }
    103     }
    104 }

    平衡树是一种很强大的数据结构,而把它可持久化以后必然让他如虎添翼,能带来更多新的题型以及新的做法。希望你能从我的博客中学到什么:)

  • 相关阅读:
    mybatis中大于等于小于等于的写法
    RandomAccess接口
    ArrayList源码解析
    使用Docker搭建MySQL主从复制(一主一从)
    狂神Docker视频学习笔记(基础篇)
    【JQ】jQuery实现将div中滚动条滚动到指定位置的方法
    JAVA线程池的基本使用
    史上最全的Java技术体系思维导图,没有之一!
    springboot整合kafka
    spring cloud alibaba 分布式事务解决方案之seata-1.3.0
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7279296.html
Copyright © 2011-2022 走看看