首页 > 其他 > 详细

可持久化数据结构学习笔记

时间:2019-02-06 14:51:25      阅读:204      评论:0      收藏:0      [点我收藏+]
/*
可持久化的迹象,我们俯身欣赏!
                  ——《膜你抄》
*/   

引子

我们在生活中可能会遇到这样的问题,要是某一变化是基于某一个历史版本而来的变化。

这样处理的过程就比较困难。(然而对于暴力这个一点都不困难)

有什么是暴力算法解决不了的呢?

又有什么暴力算法是优化不了的呢?

我们分析暴力算法的复杂度(裸暴力我们就不说了)

考虑有点技术含量的暴力:我开M个数据结构维护每一时刻的版本然后在那一时刻的版本上做操作。

Hmm...复杂度是对了,但是空间呢?大概联赛给你开放整一个内存吧。(可能还不够。。。)

我们分析这样的劣势:就是把以前一样的东西重复记录的M次

要是我们只改变有修改部分的结构就好了!!!

于是就有了可持久化数据结构:我们只记录原来数据结构中发生改变的副本,其他的留在原数据结构中。

从Trie树开始的可持久化之旅

这个首先得搞懂思想(请确保读懂上面相关知识)

在可持久化Trie树中插入一个元素的步骤一般如下:

  1. 设当前可持久化Trie树的根为lstrt(lastroot),插入元素以后的根为nowrt(nowroot)
  2. 建立一个新的节点(根)NowRoot
  3. 把nowrt下所有元素的指针所指信息置为lstrt中的所有指针信息(就是吧trie[nowrt][s]=trie[lstrt][s],s为字符所有可能,但是要除去当前字符信息)
  4. 对于当前字符信息重新维护,并新建节点new,trie[nowrt][now_char]=new(当前字符信息重新指)
  5. 令lstrt=trie[lstrt][now_char],nowrt=trie[nowrt][new_char] (重新准备迭代)
  6. 重复3-5至所有的new_char处理完毕。

这里是对于四个字符串依次插入可持久化Trie树的图,结合上述思想理解一下:

这四个字符串依次是:“abc","abd","abcd","bcd”.

技术分享图片

 

这里是一个例题:P4735 最大异或和

 

Solution:显然需要考虑前缀xor和,记为s[i]

对于询问操作 l,r , x 就是询问一个位子p∈[l-1,r-1]使s[p] xor (x xor s[n])

如果只考虑右端点限制,那么就是直接从root[r-1] 访问进去贪心选取就行,

我们再次考虑左端点的限制,那么我们记lastest[x]表示指针所指元素位子为x时,最后面元素插入时经过这个点的最大的序号。

(如果没有元素经过这个点置为最小值-1:我们坚决不访问他)

然后询问时候考虑左端点限制是在处理下一个点去哪的位置是last值必须大于等于l-1才被认为有效点,

然后剩下的贪心(走和当前位相反或者走有元素那边)就行。

Hint:本题卡常#3和#6点建议打上O2优化、快读、还有别打那么多头文件...

技术分享图片
# pragma G++ optimize(2)
# include <cstdio>
using namespace std;
const int N=600010;
int n,m,tot;
int trie[N*24][2],lastest[N*24],root[N],s[N];
inline int max(int x,int y){return (x>y)?x:y;}
inline int read() {
    static char c= getchar();
    int a= 0;
    while(c < 0 || c > 9) c= getchar();
    while(c >= 0 && c <= 9) a= a * 10 + c - 0, c= getchar();
    return a;
}
void insert(int i,int dep,int lstrt,int nowrt)
{
    if (dep<0) { lastest[nowrt]=i; return;}
    int c=(s[i]>>dep) & 1;
    if (lstrt!=0) trie[nowrt][c^1]=trie[lstrt][c^1];
    trie[nowrt][c]=++tot;
    insert(i,dep-1,trie[lstrt][c],trie[nowrt][c]);
    lastest[nowrt]=max(lastest[trie[nowrt][0]],lastest[trie[nowrt][1]]);
}
int ask(int nowrt,int val,int dep,int mark)
{
    if (dep<0) return s[lastest[nowrt]]^val;
    int c=(val>>dep) & 1;
    if (lastest[trie[nowrt][c^1]]>=mark)
        return ask(trie[nowrt][c^1],val,dep-1,mark);
    else
        return ask(trie[nowrt][c],val,dep-1,mark);
}
inline void write(int x)
{
    if (x>9) write(x/10);
    putchar(0+x%10);
}
int main()
{
    n=read();m=read();
     int t;
     lastest[0]=-1; root[0]=++tot;
    insert(0,23,0,root[0]);
    for (int i=1;i<=n;i++) {
        t=read(); s[i]=s[i-1]^t;
        root[i]=++tot;
        insert(i,23,root[i-1],root[i]);
    }
    char op[3];
    for (int i=1;i<=m;i++) {
        scanf("%s",op);
        if (op[0]==A) {
            int x=read();
            root[++n]=++tot;
            s[n]=s[n-1]^x;
            insert(n,23,root[n-1],root[n]);
        } else {
            int l=read(),r=read(),x=read();
            write(ask(root[r-1],x^s[n],23,l-1));
            putchar(\n);
        }
    }
    return 0;
}
View Code

 

可持久化数据结构学习笔记

原文:https://www.cnblogs.com/ljc20020730/p/10353707.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!