可持久化0-1Trie树

我跟可持久化数据结构杠上了 \(QwQ\) 。三天模拟赛考了两次可持久化数据结构(主席树、可持久化0-1Trie树),woc


目录:

  • 个人理解
  • 时空复杂度分析
  • 例题及简析

一、个人理解

可持久化0-1Trie树,是一种可以快速查询区间异或信息的高级数据结构。

它的主要思想和主席树相同,即保存每次插入操作的历史版本,来快速查询区间的异或信息。

0-1Trie树和平常写的strTrie树相同,都是维护前缀信息的数据结构。不同点只有一个,就是0-1Trie树是维护一个0-1串。可持久化0-1Trie树运用了贪心的思想,即将序列里的 \(X\) 按二进制为拆分,若当前 \(X_i\) (指 \(X\) 二进制拆分后的第 \(i\) 位)是1,我们就往0-1Trie树的0边走;反之就往0-1Trie树的1边走。

可持久化0-1Trie树与主席树相同,也需要动态开点。

注意:维护区间异或信息的不止可持久化0-1Trie树一种,还有线性基等。


二、时空复杂度分析:

  1. 时间复杂度:

    与普通0-1Trie树相同:\(O(n\log n)\) 。

    :strTrie树的时间复杂度是 \(O(n)\) ,是一种典型的以时间换空间的算法。

  2. 空间复杂度:
    与普通的0-1Trie树相同:\(O(\min\{n\log |f(a_i)|,|f(a_i)|\})\) ( \(|f(a_i)|\) 为值域)。注意常数为 \(2^5\) (1<<5)。

三、例题及简析

  1. P4735 最大异或和

    Description:

    给定数列 \(\{a_n\}\) ,支持两种操作:

    • 在数列尾添加一个数 \(x\) ,数列长度变成 \(n+1\) ;
    • 给定闭区间 \([l,r]\) 和一个数 \(x\) ,求:
      \[
      \max_{i=l}^{r}\left \{\left(\bigoplus_{j=i}^{n}a_j \right)\bigoplus x\right \}
      \]

    Method:

    定义 \(Xorsum_i\) 为 \(\bigoplus_{i=1}^{n}a_i\) ,即前缀异或和。我们显然可以得到
    \[
    \left(\bigoplus_{i=pos}^{n}a_i\right)\bigoplus x=Xorsum_{pos-1}\bigoplus Xorsum_n \bigoplus x
    \]

    :\(x\bigoplus x=0\) , \(x \bigoplus 0=x\) 。

    我们发现 \(Xorsum_n\bigoplus x\) 是一个定值,我们只需要维护 \(Xorsum_{pos-1}\) 即可。

    考虑用可持久化0-1Trie树维护。与主席树思路相同 ,我们建立 \(n+1\) 个版本的0-1Trie树,查询的时候运用贪心的思路即可。

    可持久化线段树同样支持“前缀和”的思想,我们最后只需要在第 \(r\) 个版本的0-1Trie树上查找 \(l\) 位置即可。

    本题毒瘤卡常,本人人丑常数大,用了fread等各种卡常操作才通过。并且由于luogu评测姬的原因(大雾,已经通过的代码又会T掉woc。卡不过的话,开o2吧。

    Code:

    #include<bits/stdc++.h>
    #define Maxn 600010
    #define Maxdep 23
    #define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    char buf[1<<21],*p1=buf,*p2=buf;
    inline void read(int &x)
    {
        int f=1;x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        x*=f;
    }
    int n,m;
    int sum[Maxn];
    struct trie
    {
        trie *chd[2];
        int symbl;
        trie()
        {
            for(int i=0;i<2;i++) chd[i]=NULL;
            symbl=0;
        }
    }*root[Maxn],tree[Maxn<<5],*tail;
    void Init(){tail=tree;}
    void build(trie *&p,int dep)
    {
        p=new (tail++)trie();
        if(dep<0) return ;
        build(p->chd[0],dep-1);
    }
    void update(trie *&p,trie *flag,int dep,int i)
    {
        p=new (tail++)trie();
        if(flag) *p=*flag;
        if(dep<0) return (void)(p->symbl=i);
        int tmp=(sum[i]>>dep)&1;//判断是1还是0
        if(!tmp) update(p->chd[0],flag?flag->chd[0]:NULL,dep-1,i);
        else update(p->chd[1],flag?flag->chd[1]:NULL,dep-1,i);
        if(p->chd[0]) p->symbl=std::max(p->symbl,p->chd[0]->symbl);
        if(p->chd[1]) p->symbl=std::max(p->symbl,p->chd[1]->symbl);
    }
    int query(trie *p,int x,int dep,int limit)
    {
        if(dep<0) return sum[p->symbl]^x;
        int tmp=(x>>dep)&1;
        if(p->chd[tmp^1]&&p->chd[tmp^1]->symbl>=limit) return query(p->chd[tmp^1],x,dep-1,limit);
        return query(p->chd[tmp],x,dep-1,limit);
    }
    signed main()
    {
        Init();
        read(n),read(m);
        build(root[0],Maxdep);
        for(int i=1,x;i<=n;i++)
        {
            read(x);
            sum[i]=sum[i-1]^x;
            update(root[i],root[i-1],Maxdep,i);
        }
        for(int i=1;i<=m;i++)
        {
            char ch=getchar();
            while(ch!='A'&&ch!='Q') ch=getchar();
            if(ch=='A')
            {
                int x;
                read(x);
                n++;
                sum[n]=sum[n-1]^x;
                update(root[n],root[n-1],Maxdep,n);
                continue;
            }
            if(ch=='Q')
            {
                int l,r,x;
                read(l),read(r),read(x);
                int ans=query(root[r-1],sum[n]^x,Maxdep,l-1);
                printf("%d\n",ans);
                continue;
            }
        }
        return 0;
    }

原文地址:https://www.cnblogs.com/nth-element/p/11773667.html

时间: 2024-07-31 00:14:50

可持久化0-1Trie树的相关文章

P5283 [十二省联考2019]异或粽子 可持久化01Trie+线段树

$ \color{#0066ff}{ 题目描述 }$ 小粽是一个喜欢吃粽子的好孩子.今天她在家里自己做起了粽子. 小粽面前有 \(n\) 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 \(1\) 到 \(n\).第 \(i\) 种馅儿具有一个非负整数的属性值 \(a_i\).每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子.小粽准备用这些馅儿来做出 \(k\) 个粽子. 小粽的做法是:选两个整数数 \(l\), \(r\),满足 \(1 \leqslant l

POJ2449【A*算法】【可持久化左偏树】

K短路模板题.K很小所以A*就可以过了. /* I will wait for you */ #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <algorithm> #include <iostream> #include <fstream> #include &

LUOGU P3919 【模板】可持久化数组(主席树)

传送门 解题思路 给每一时刻建一棵线段树维护当前时刻的值,然后修改的时候直接修改,查询的时候直接查,记住查询完后一定要复制. 代码 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> using namespace std; const int MAXN = 1000005; inline int rd(){ int x=0

【bzoj4026】dC Loves Number Theory 可持久化线段树

题目描述 dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯竭的水题资源. 给定一个长度为 n的正整数序列A,有q次询问,每次询问一段区间内所有元素乘积的φ(φ(n)代表1~n 中与n互质的数的个数) .由于答案可能很大,所以请对答案 mod 10^6 + 777. (本题强制在线,所有询问操作的l,r都需要 xor上一次询问的答案 lastans,初始时,lastans = 0) 输入 第一行,两个正整数,N,Q,表示序列的长度和询问的个数. 第二行有N 个正

Codeforces 706D Vasiliy&#39;s Multiset(可持久化字典树)

[题目链接] http://codeforces.com/problemset/problem/706/D [题目大意] 要求实现一个集合中的三个操作,1:在集合中加入一个元素x,2:从集合中删除一个元素x(保证x存在),3:要求从集合中选出一个数,使得其与给出的数x的异或值最大,输出这个异或值. [题解] 可以将所有的以二进制形式存在01字典树上,删除即插入权值为-1的二进制串,对于异或值最大的操作,我们只要在字典树上按位贪心,从最高位开始尽量保证该位存在最后就能得到答案.写代码的时候直接写了

BZOJ5338 [TJOI2018] Xor 【可持久化Trie树】【dfs序】

题目分析: 很无聊的一道题目.首先区间内单点对应异或值的询问容易想到trie树.由于题目在树上进行,case1将路径分成两段,然后dfs的时候顺便可持久化trie树做询问.case2维护dfs序,对dfs序建可持久化的trie树.这样做的空间复杂度是O(nw),时间复杂度是O(nw). 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=102000; 5 6 int n,q; 7 int v[maxn

【模板】主席树

主席树..高大上的名字..原名叫可持久化线段树..也有人叫函数式线段树(其实叫什么都不重要). 本来的作用就是字面意思..持久化的线段树,支持修改之后查找某次修改之前的版本.(在NOIP之前在算法导论上看到过,当时觉得没什么,现在才知道好厉害的数据结构) 具体来怎么实现呢..其实就是每次修改的时候都新开一个根节点然后把和修改有关的区间一路新建下去,与修改无关的区间就继承上次修改版本的节点,这样会节省空间. 来应用一下,一个基础的应用就是区间K小值查询(poj2104).即给定一个序列,给出L,R

【清澄A1333】【整体二分+二维树状数组】矩阵乘法(梁盾)

试题来源 2012中国国家集训队命题答辩 问题描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入格式 第一行两个数N,Q,表示矩阵大小和询问组数: 接下来N行N列一共N*N个数,表示这个矩阵: 再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角.以(x2,y2)为右下角的子矩形中的第K小数. 输出格式 对于每组询问输出第K小的数. 样例输入 2 2 2 1 3 4 1 2 1 2 1 1 1 2 2 3 样例输出 1

zoj 2112 Dynamic Rankings(树状数组套主席树)

题意:对于一段区间,每次求[l,r]的第k大,存在单点修改操作: 思路: 学习主席树参考: http://blog.csdn.net/wjf_wzzc/article/details/24560117(各种形式) http://blog.csdn.net/bossup/article/details/31921235(推荐) http://blog.csdn.net/xiaofengcanyuexj/article/details/25553521?utm_source=tuicool(图解)

可持久化并查集总结

可持久化并查集总结 标签: 数据结构--可持久化--可持久化并查集 阅读体验:https://www.zybuluo.com/Junlier/note/1268670 前面的话 其实看起来很高大上,最后还不是沦为被我这种菜鸡都能学会的东西 嗯,我只是想解释这个并不是很难...连我这么弱都... 然后还是以模板题为背景将比较好...洛谷题目传送门 实现方法 其实可持久化并查集就是要支持回到以前的版本(类比可持久化$数组/线段树$之类的) 那么我都类比了,很显然就是用主席树来维护吧 主席树部分 我们