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

可持久化 0/1 Trie

时间:2024-07-02 15:21:48浏览次数:14  
标签:p2 p1 持久 Trie int lson return data

可持久化可以维护数据结构的历史版本。

对于一个字典树, 如果更改一个元素, 暴力做法是复制一个树, 让后在树上修改。其实, 这样是有很多个一定一样的点是浪费的, 真正被修改的是 \(\log_2n\) 个点, \(2\log_2n\) 条边。

优点 : 大大减低时间复杂度,还支持在线做。

缺点 : 不能传懒标记, 不知道懒标记是修改哪个版本留下的

可持久化0/1 Trie, 例题 : P3835

#include<bits/stdc++.h>

using namespace std;

const int N = 5e5 + 5, IP = 1e9;

struct TRIE{
  int cnt, son[2];
  void clear(){
    cnt = son[0] = son[1] = 0;
  }
}trie[N * 62];

int tot, ans, x, p, n, v, op, c, root[N], rak;

int push_back(){
  trie[++tot].clear();
  return tot;
}

void Insert(int p, int q, int x){
  for(int i = 30; ~i; i--){
    for(int j = 0; j <= 1; ++j){
      if(!trie[q].son[j]){
        trie[q].son[j] = push_back();
      }
    }
    c = bool((1 << i) & x);
    trie[p].son[c] = push_back();
    trie[p].son[!c] = trie[q].son[!c];
    p = trie[p].son[c], q = trie[q].son[c];
    trie[p].cnt = trie[q].cnt + 1;
  }
}

void Erase(int p, int q, int x){
  for(int i = 30; ~i; i--){
    for(int j = 0; j <= 1; ++j){
      if(!trie[q].son[j]){
        trie[q].son[j] = push_back();
      }
    }
    c = bool((1 << i) & x);
    trie[p].son[c] = push_back();
    trie[p].son[!c] = trie[q].son[!c];
    p = trie[p].son[c], q = trie[q].son[c];
    trie[p].cnt = trie[q].cnt - 1;
  }
}

int S3(int p, int x){
  ans = 0;
  for(int i = 30; ~i; i--){
    c = bool((1 << i) & x);
    if(c){
      ans += trie[trie[p].son[0]].cnt;
    }
    p = trie[p].son[c];
  }
  return ans + 1;
}

int S4(int p, int x){
  ans = 0;
  for(int i = 30; ~i; i--){
    if(trie[trie[p].son[0]].cnt >= x){
      p = trie[p].son[0];
    }
    else{
      x -= trie[trie[p].son[0]].cnt;
      p = trie[p].son[1];
      ans |= (1 << i);
    }
  }
  return ans;
}

int query(int p, int q, int x){
  for(int i = 30; ~i; i--){
    c = bool((1 << i) & x);
    p = trie[p].son[c], q = trie[q].son[c];
  }
  return trie[q].cnt - trie[p].cnt;
}

int main(){
  cin >> n;
  root[0] = push_back();
  for(int i = 1; i <= n; i++){
    cin >> v >> op >> x;
    if(op <= 2){
      root[i] = push_back();
    }
    else{
      root[i] = root[v];
    }
    if(op == 1){
      Insert(root[i], root[v], x + IP);
    }
    if(op == 2){
      if(query(root[i], root[v], x + IP)){
        Erase(root[i], root[v], x + IP);
      }
      else{
        root[i] = root[v];
      }
    }
    if(op == 3){
      cout << S3(root[i], x + IP) << '\n';
    }
    if(op == 4){
      cout << S4(root[i], x) - IP << '\n';
    }
    if(op == 5){
      rak = S3(root[i], x + IP) - 1;
      cout << S4(root[i], rak) - IP << '\n';
    }
    if(op == 6){
      rak = S3(root[i], x + IP + 1);
      cout << S4(root[i], rak) - IP << '\n';
    }
  }
  return 0;
}

可持久化线段树, 例题 : P3834

#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 5;

struct Node{
  int l, r, lson, rson, data;
}t[25 * N];

int tot, n, m, root[N], a[N], b[N], l, r, k;

int push_back(){
  t[++tot] = {0, 0, 0, 0, 0};
  return tot;
}

void renew(int p){
  t[p].data = t[t[p].lson].data + t[t[p].rson].data;
}

void build(int p, int l, int r){
  t[p].l = l, t[p].r = r;
  if(l == r){
    return;
  }
  int mid = (l + r) >> 1;
  t[p].lson = push_back(), t[p].rson = push_back();
  build(t[p].lson, l, mid);
  build(t[p].rson, mid + 1, r);
  renew(p);
}

void updata(int p1, int p2, int ok){
  t[p2] = t[p1];
  if(t[p2].l == t[p2].r){
    t[p2].data++;
    return;
  }
  int mid = (t[p1].l + t[p1].r) >> 1;
  if(ok <= mid){
    t[p2].lson = push_back();
    updata(t[p1].lson, t[p2].lson, ok);
  }
  else{
    t[p2].rson = push_back();
    updata(t[p1].rson, t[p2].rson, ok);
  }
  renew(p2);
}

int query(int p1, int p2, int ok){
  if(t[p2].l == t[p2].r){
    return t[p2].l;
  }
  int mid = (t[p2].l + t[p2].r) >> 1;
  if(t[t[p2].lson].data - t[t[p1].lson].data >= ok){
    return query(t[p1].lson, t[p2].lson, ok);
  }
  return query(t[p1].rson, t[p2].rson, ok - (t[t[p2].lson].data - t[t[p1].lson].data));
}

int main(){
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> m;
  root[0] = push_back();
  build(1, 1, n);
  for(int i = 1; i <= n; ++i){
    cin >> a[i];
    b[i] = a[i];
  }
  sort(b + 1, b + n + 1);
  for(int i = 1; i <= n; ++i){
    a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
    root[i] = push_back();
    updata(root[i - 1], root[i], a[i]);
  }
  for(int i = 1; i <= m; ++i){
    cin >> l >> r >> k;
    cout << b[query(root[l - 1], root[r], k)] << '\n';
  }
  return 0;
}

标签:p2,p1,持久,Trie,int,lson,return,data
From: https://www.cnblogs.com/liuyichen0401/p/18269259

相关文章

  • CF950Div3 G. Yasya and the Mysterious Tree(01Trie)
    Problem题目地址Solution设\(s[u]\)是根到\(u\)路径上的异或和,树上任意两点\(u,v\)的路径异或和可表示为\(s[u]\opluss[v]\)。考虑查询操作?vx即求\(\max\{s[v]\opluss[u]\oplusx|\\1\leu\len,u\not=v\}\),若把\(s[v]\oplusx\)看作一个整体......
  • 十一、Redis持久化之AOF
    文章目录一、AOF(AppendOnlyFile)1.1是什么1.2AOF持久化流程1.3AOF默认不开启1.4AOF和RDB同时开启,redis听谁的?1.5AOF启动/修复/恢复1.6AOF同步频率设置1.7Rewrite压缩1.8优势1.9劣势1.10小总结二、总结(Whichone)2.1用哪个好2.2官网建议上一篇十、Red......
  • 十、Redis持久化之RDB
    文章目录一、总体介绍二、RDB(RedisDataBase)2.1官网介绍2.2RDB是什么2.3备份是如何执行的2.4Fork2.5RDB持久化流程2.6dump.rdb文件2.7配置位置2.8如何触发RDB快照;保持策略2.8.1配置文件中默认的快照配置2.8.2命令saveVSbgsave2.8.3flushall命令2.8.4SNAPSHO......
  • 慢查询、pipline、发布订阅、 bitmap位图、 hyperloglog、geo、持久化
    【慢查询】1#1我们配置一个时间,如果查询时间超过了我们设置的时间,我们就认为这是一个慢查询2#2慢查询是一个先进先出的队列,固定长度,保存在内存中--->通过设置慢查询,以后超过我们设置时间的命令,就会放在这个队列中3#3后期我们通过查询这个队列,过滤出慢命令--》......
  • 数据结构 —— Trie 树
    一个笔记需要一张头图:Trie树是一种维护(广义)字符串(我们认为广义字符串是一切可以被线性描述的类型,例如,我们认为整数(无论是哪种进制下)是一种广义字符串;有理数也是一种广义字符串(使用无限循环小数方式表述,可能需要一些特殊处理。))的数据结构,其特征为适于处理前缀类型或寻找类型(i.e.......
  • 【Redis持久化】RDB、AOF介绍和使用
    RDB、AOF介绍和使用引言ROB介绍配置指令介绍使用指令:dump文件修复指令快照禁用AOF工作流程:文件重写:三种写回策略:混合使用引言持久化的目的,其实就是在Redis重启或者中途崩溃的时候能够依靠自身恢复数据,而不需要再次访问MySQL数据库,重新取得数据,增加MySQL的工作量。在此有两种方法,R......
  • MySQL Public Key Retrieval is not allowed 解决指南
    MySQLPublicKeyRetrievalisnotallowed解决指南基本概念与作用说明完整代码示例与解决方案示例一:检查用户权限示例二:检查KMS配置示例三:检查加密列定义示例四:重置密钥功能使用思路与最佳实践实际工作开发技巧在现代数据库管理中,加密和密钥管理是保障数据安全......
  • python爬虫之基于终端指令的持久化存储
    python爬虫之基于终端指令的持久化存储scrapy持久化存储基于终端指令:1、要求:只可以将parse方法的返回值存储到本地的文本文件中2、注意:持久化存储对应的文本文件类型只可以为:‘json’,‘jsonlines’,‘jsonl’,‘jl’,‘csv’,‘xml’,‘marshal’,‘pickle’3......
  • 认识Retrieval Augmented Generation(RAG)
    什么是RAG?Retrieval-AugmentedGeneration(RAG)是一种结合信息检索和生成式AI技术的框架。它通过从外部数据源检索信息,增强语言模型(如GPT-3)的生成能力,从而提供更加准确和相关的回答。RAG的组成部分信息检索模块(Retriever)功能:从预先构建的知识库或文档库中检索与用......
  • 使用 localStorage 持久化用户登录状态
    在现代Web应用中,保持用户的登录状态是一个非常重要的功能。本文将介绍如何使用localStorage和Vuex在用户登录后持久化登录状态,并在页面刷新后保持用户的登录状态。1.store/index.jsimportVuefrom'vue';importVuexfrom'vuex';Vue.use(Vuex);exportdefaultnewV......