zoukankan      html  css  js  c++  java
  • 可持久化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(nlog n))

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

    2. 空间复杂度:
      与普通的0-1Trie树相同:(O(min{nlog |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(igoplus_{j=i}^{n}a_j ight)igoplus x ight } ]

      Method:

      定义 (Xorsum_i)(igoplus_{i=1}^{n}a_i) ,即前缀异或和。我们显然可以得到

      [left(igoplus_{i=pos}^{n}a_i ight)igoplus x=Xorsum_{pos-1}igoplus Xorsum_n igoplus x ]

      (xigoplus x=0) , (x igoplus 0=x)

      我们发现 (Xorsum_nigoplus 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
      ",ans);
      			continue;
      		}
      	}
      	return 0;
      }
      
  • 相关阅读:
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
    小D课堂
  • 原文地址:https://www.cnblogs.com/nth-element/p/11773667.html
Copyright © 2011-2022 走看看