首页 > 其他分享 >可持久化Trie

可持久化Trie

时间:2024-12-09 21:32:47浏览次数:3  
标签:sz ch 持久 Trie int trie id

可持久化Trie--区间异或最值问题

应用:在 \(O(logn)\) 时间复杂度解决 查询区间 \([l,r]\) 内与数 \(x\) 异或的最大值。

插入操作:把 \(n\) 个整数插入 \(01Trie\),生成 \(n\) 个版本的可持久化树。

查询操作:利用前缀和与差分的思想,用两颗前缀 \(Trie\) 树相减得到该区间的 \(Trie\) 树。查询的时候,利用贪心思想,尽量与当前位不同的地方跳即可。

模板

//可持久化Trie
struct Trie{
   int ch[N<<5][2];
   int rt[N];
   int sz[N<<5];
   int idx=0,cnt=0;
   void insert(int v){
      rt[++idx]=++cnt;//新根开点
      int x=rt[idx-1];//旧版
      int y=rt[idx];
      for(int i=30;i>=0;i--){
         int j=v>>i&1;
         ch[y][j^1]=ch[x][j^1];//异位继承
         ch[y][j]=++cnt;//新位
         x=ch[x][j];y=ch[y][j];
         sz[y]=sz[x]+1;
      }
   }
   int query(int x,int y,int v){
      int ret=0;
      for(int i=30;i>=0;i--){
         int j=(v>>i&1);
         if(sz[ch[y][j^1]]>sz[ch[x][j^1]])
            x=ch[x][j^1],y=ch[y][j^1],ret|=(1LL<<i);
         else
            x=ch[x][j],y=ch[y][j];
      }
      return ret;
   }
}trie;

查询 \([l,r]\) 与 \(x\) 的最大异或值时: \(query(trie.rt[l-1],trie.rt[r])\)

P4592 [TJOI2018] 异或 树链剖分+可持久化Trie

题目链接

一道模板题,解决区间异或最大值--可持久化Trie。然后用树链剖分把树上问题转化成链上问题即可。

注意插入的时候要按照 \(dfs\) 序插入Trie中。

#include<bits/stdc++.h>

using namespace std;

using i64=long long;

const int N =1e5+10;

int a[N];

//可持久化Trie
struct Trie{
   int ch[N<<5][2];
   int rt[N];
   int sz[N<<5];
   int idx=0,cnt=0;
   void insert(int v){
      rt[++idx]=++cnt;//新根开点
      int x=rt[idx-1];//旧版
      int y=rt[idx];
      for(int i=30;i>=0;i--){
         int j=v>>i&1;
         ch[y][j^1]=ch[x][j^1];//异位继承
         ch[y][j]=++cnt;//新位
         x=ch[x][j];y=ch[y][j];
         sz[y]=sz[x]+1;
      }
   }
   int query(int x,int y,int v){
      int ret=0;
      for(int i=30;i>=0;i--){
         int j=(v>>i&1);
         if(sz[ch[y][j^1]]>sz[ch[x][j^1]])
            x=ch[x][j^1],y=ch[y][j^1],ret|=(1LL<<i);
         else
            x=ch[x][j],y=ch[y][j];
      }
      return ret;
   }
}trie;

//树链剖分
vector<int> e[N];
int fa[N],dep[N],son[N],sz[N],id[N],w[N];
int top[N],dfn;
//预处理各个信息
void dfs1(int u,int father){
    fa[u]=father;
    dep[u]=dep[father]+1;
    sz[u]=1;
    for(auto v:e[u]){
        if(v==father) continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[son[u]]<sz[v]) son[u]=v;
    }
}

void dfs2(int u,int tp){
    id[u]=++dfn;
    w[dfn]=a[u];
    top[u]=tp;
    if(!son[u]) return;
    dfs2(son[u],tp);
    for(auto v:e[u]){
        if(v==fa[u]||v==son[u]) continue;
        dfs2(v,v);
    }
}

int qRange(int u,int v,int val){
    int res=0,l,r;
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        //线段树区间查询[id[top[u]],id[u]]
        l=trie.rt[id[top[u]]-1];
        r=trie.rt[id[u]];
        res=max(res,trie.query(l,r,val));
        u=fa[top[u]];
    }
    if(dep[u]>dep[v]) swap(u,v);
    //加上两点之间的答案[id[u],id[v]]
    l=trie.rt[id[u]-1];
    r=trie.rt[id[v]];
    res=max(res,trie.query(l,r,val));
    return res;
}

int qSon(int u,int v){
    //线段树查询[id[u],id[u]+sz[u]-1]
    int l=trie.rt[id[u]-1],r=trie.rt[id[u]+sz[u]-1];
    return trie.query(l,r,v);
}

void Showball(){
    int n,q;
    cin>>n>>q;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs1(1,-1);
    dfs2(1,1);
    vector<int> p(n+1);
    iota(p.begin(),p.end(),0);
    sort(p.begin()+1,p.end(),[&](int x,int y){
        return id[x]<id[y];
    });
    for(int i=1;i<=n;i++){
        trie.insert(a[p[i]]);
    }

    while(q--){
        int op;
        cin>>op;
        if(op==1){
            int x,z;
            cin>>x>>z;
            cout<<qSon(x,z)<<"\n";
        }else{
            int x,y,z;
            cin>>x>>y>>z;
            cout<<qRange(x,y,z)<<"\n";
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t=1;
    //cin>>t;

    while(t--){
      Showball();
    }

    return 0;
}

标签:sz,ch,持久,Trie,int,trie,id
From: https://www.cnblogs.com/showball/p/18596077

相关文章

  • RAG(Retrieval-Augmented Generation)评估面试题
    1.评估检索增强生成(RAG)系统的三个关键指标是什么?检索增强生成(RAG)系统的三个关键评估指标为:上下文相关性:评估检索到的文档与输入查询的匹配程度。高上下文相关性确保检索到的信息切题,并充分涵盖查询内容。忠实度:衡量生成的响应与检索到的文档之间的一致性。忠实度确保输出......
  • 面经自测——MySQL联合索引/事务的四大特性/持久性怎么做/说一下MySQL日志
    前言本文是作者专门用来自测Java后端相关面试题的,所有问题都是在牛客、知识星球或网上找到的最近最新的面试题,全文回答都是作者按自己的真实水平仿照真实环境的回答,所以答案不一定真实(但回答一定真诚......
  • **如何利用WikipediaRetriever进行高效信息检索**
    引言在AI应用的开发过程中,信息的检索和处理显得尤为重要。WikipediaRetriever是一个强大的工具,能够帮助开发者从Wikipedia中提取有用的信息。这篇文章旨在介绍如何使用WikipediaRetriever进行信息检索,并整合到您的AI和编程项目中。主要内容WikipediaRetriever概述Wikipe......
  • pinia 持久化存储库pinia-plugin-persist使用
    对于Vue3和Pinia,有一个名为pinia-plugin-persist的插件可以用来持久化Piniastore的状态到localStorage或sessionStorage。这个插件简化了状态持久化的过程,使得你不需要手动编写保存和加载状态的逻辑。以下是如何使用pinia-plugin-persist插件来持久化Piniastore......
  • 解题报告-论对“区间可持久化”的新理解
    解题报告-论对“区间可持久化”的新理解当我第一眼看到“可持久化\(\texttt{Trie}\)”的时候,我以为这不过是一个\(\texttt{Trie}\)+可持久化罢了。事实证明也是这样,在后面的代码实现中,我也是一遍打对了这个紫色板子。那么,一道模板题,有什么好说的?正是因为控住我的不是模板,这道......
  • 【数据结构】 字典树trie详解
    定义:将多个字符串以树的方式存储即为字典树,如图,\(1,4,3,12\)表示\(cca\),我么用\(ch[i][j]\)来表示第\(i\)个节点的\(j\)字符所指向的下一个节点,\(tag[u]\)表示节点\(u\)是否代表一个字符串的结尾,如果是的话,\(tag[u]=1\)。模板CODE添加字符串//n表示即将要向字典......
  • AI - RAG(Retrieval-Augmented Generation,检索增强生成)
    RAG(Retrieval-Augmented Generation,检索增强生成)技术是一种结合了检索和生成功能的自然语言处理(NLP)技术。它通过从大型外部数据库中检索与输入问题相关的信息,来辅助生成模型回答问题。以下是对RAG技术的详细解析:一、技术原理RAG技术的核心思想是将传统的检索技术与现代的自然语......
  • 字典树-trie
    (发文的目的是为了记录学习算法的历程,而不是教程)引子如果想要再字典里查找“salieri”这个单词,我们会怎么做,比较朴素(bushi)的想法是从字典的第一个单词翻到最后一个单词,这种方法虽然(蠢)简单,但是却很花时间,当然,聪明(正常)的你肯定会按照索引来查找,而字典树正是借用了这种索引的思想。......
  • Trie树-字典树笔记
    Trie树-字典树笔记Trie树是一种高效的存储字符串的数据结构,它将多个字符串的前缀合并在一条边上,每次插入时,都判断当前的树上有无能够重合的前缀,如果没有就单独增加一个节点。通过合并前缀,可以做到快速查找已经优化空间的操作。下面是使用数组模拟实现Trie树的部分代码:我们首先......
  • 服务重启了,如何保证线程池中的数据不丢失方案 - 提前做持久化
    服务重启了,如何保证线程池中的数据不丢失方案方案:提前做持久化1.用户请求过来之后,先处理业务逻辑1,紧接着向DB中写入一条任务数据,状态是:待执行。2.然后将查出的任务提交到线程池中,由它处理业务逻辑2。3.处理成功之后,修改任务的待执行状态为:已执行。 需要注意的是:业务逻辑2的处理......