[学习笔记]后缀平衡树
后缀数组+平衡树=后缀平衡树
支持动态插入字符(只能往前插入),即插入一个后缀,维护所有后缀的排名
插入后缀找到位置?平衡树上二分
法一:
哈希+二分,太慢
法二:
第一个字符不同,已经可以比较,否则比较第二个字符开始的后缀,之前这两个后缀排名已经处理好了。直接比较排名即可。
查询任意位置的排名?
法一:
暴力这个点往上跳log次,找到rank
法二:
每个点打一个tag,把排名“绝对化”
记录[l,r],val,表示x子树的tag值域区间和x的值val,val=(l+r)/2
这样可以O(1)查排名
总值域是[1,inf],深度logn,所以开个double一定精度没有问题。
具体用重量平衡树维护(子树大小期望logn,如treap或者SGT),SGT就可以啦
这样直接重构的时候把[l,r]tag重新赋值。(treap旋转时候必须直接重构。否则tag就乱了)
优点:
相较于LCT+SAM,可以离线,可以可持久化
例题
都挺裸的。。。
bzoj3682: Phorni
线段树维护区间字典序最小的id即可
注意:
由于tag或者排名是不断变化的,不能记录tag的值,只要记录id是哪一个即可。
因为新插入后缀,相对排名不影响
改变某一个pos[x]只会影响到根的结果。
pushup时候现场比较
#include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define mk(a,b) make_pair(a,b) #define numb (ch^'0') #define pb push_back #define solid const auto & #define enter cout<<endl #define pii pair<int,int> using namespace std; typedef long long ll; template<class T>il void rd(T &x){char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x); } template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');} template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');} template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}namespace Miracle{ const int N=500000+5; const int M=1000000+5; const double inf=1e18; const double alp=0.75; #define mid ((l+r)>>1) #define Md ((L+R)/2.0) int n,q,m,typ; int pos[N]; char s[M]; int rt; namespace SGT{ struct node{int ch[2];int sz;double l,r;double val;void init(double L,double R){sz=1;ch[0]=ch[1]=0;l=L;r=R;val=(L+R)/2;} }t[M]; int tot; #define ls t[x].ch[0] #define rs t[x].ch[1] void pushup(int x){if(!x) return;t[x].sz=t[ls].sz+t[rs].sz+1; } bool isbad(int x){return (t[ls].sz>t[x].sz*alp||t[rs].sz>t[x].sz*alp); } int q[M],num; void dfs(int x){if(!x) return;dfs(ls);q[++num]=x;dfs(rs); } int build(int l,int r,double L,double R){if(l>r) return 0;int x=q[mid];t[x].init(L,R);ls=build(l,mid-1,L,Md);rs=build(mid+1,r,Md,R);pushup(x);return x; } void rebuild(int &x){num=0;dfs(x);x=build(1,num,t[x].l,t[x].r); } int sta[M],top; void che(){for(reg i=1;i<=top;++i){if(isbad(sta[i])){if(i==1) rebuild(rt);else rebuild(t[sta[i-1]].ch[t[sta[i-1]].ch[1]==sta[i]]),pushup(sta[i-1]);return;}} } bool cmp(int x,int y){//x<y?if(s[x]!=s[y]) return s[x]<s[y];return t[x-1].val<t[y-1].val; } void ins(int p){//x is pos++tot;if(!rt){rt=tot;t[tot].init(1,inf);return;}int x=rt;top=0;while(1){int d=cmp(x,p);sta[++top]=x;++t[x].sz;if(!t[x].ch[d]){t[x].ch[d]=tot;if(d==1){//rson t[tot].init(t[x].val,t[x].r);}else{t[tot].init(t[x].l,t[x].val);}break;}x=t[x].ch[d];}che(); } void pb(int x){ins(x); } #undef ls #undef rs } namespace SMT{ #define ls (x<<1) #define rs (x<<1|1) struct node{int id; }t[4*N]; int chm(int x,int y){return SGT::t[pos[x]].val<=SGT::t[pos[y]].val?x:y; } void pushup(int x){t[x].id=chm(t[ls].id,t[rs].id); } void build(int x,int l,int r){if(l==r){t[x].id=l;return;}build(ls,l,mid);build(rs,mid+1,r);pushup(x); } void upda(int x,int l,int r,int p){if(l==r){t[x].id=l;return;}if(p<=mid) upda(ls,l,mid,p);else upda(rs,mid+1,r,p);pushup(x); } int query(int x,int l,int r,int L,int R){if(L<=l&&r<=R){return t[x].id;}if(L>mid) return query(rs,mid+1,r,L,R);if(R<=mid) return query(ls,l,mid,L,R);return chm(query(ls,l,mid,L,R),query(rs,mid+1,r,L,R)); }} int main(){rd(n);rd(q);rd(m);rd(typ);scanf("%s",s+1);reverse(s+1,s+m+1);for(reg i=1;i<=n;++i){rd(pos[i]);}for(reg i=1;i<=m;++i){SGT::pb(i);}SMT::build(1,1,n);char ch[233];int x,y;int lasans=0;while(q--){scanf("%s",ch);if(ch[0]=='I'){rd(x);if(typ) x=x^lasans;s[++m]='a'+x;SGT::pb(m);}else if(ch[0]=='C'){rd(x);rd(y);pos[x]=y;SMT::upda(1,1,n,x);}else if(ch[0]=='Q'){//warning!!! rd(x);rd(y);int now=SMT::query(1,1,n,x,y);lasans=now;printf("%d\n",lasans);//update lasans }}return 0; }} signed main(){Miracle::main();return 0; }/*Author: *Miracle* */
View Code
例题2
维护一个栈,支持末尾添加删除字符
每次询问一个区间中,另一个输入的串的出现次数
• ? ≤ 5 × 10^5, ∑ ? ≤ 5 × 10
一个模式串在主串出现位置,一定是后缀数组sa数组的一段区间
可以在后缀平衡树上找到这个区间
找LCP用哈希+二分
但是是主串的一部分?
差分!变成前缀出现次数相减
可持久化后缀平衡树
但是还有删除字符,所以可持久化是树形结构而不是链,
每次还要倍增找到要差分的节点。
UOJ101
• 维护 ? 个字符串变量,要求支持
• 某个字符串末尾加字符
• 用一个字符串覆盖另一个字符串
• 询问 ? 有几个子串,可通过 ? 时刻的串 ? 在开头加上 ?, ? 内的字符得到
• 询问 ? 有几个子串,可通过给出的串 ? 在开头加上 ?, ? 内的字符得到
• ?, ? ≤ 10^6,强制在线
和上一题差不多
第三第四个询问,就算是加上[l,r]字符,还是一个区间,依然可以暴力二分
还要可持久化
恶心恶心
转载于:https://www.cnblogs.com/Miracevin/p/10848708.html
[学习笔记]后缀平衡树相关推荐
- [学习笔记]后缀数组
参考: 后缀数组 最详细讲解 上面一篇是转载这一篇的: 后缀数组 学习笔记 一. 后缀:suff(i),后缀要排序 sa[i],排名为i的后缀开始位置 rk[i],i开始位置的后缀的排名. rk[sa ...
- [学习笔记]后缀自动机
解决大部分字符串问题的大杀器 给一下clj课件:戳我 SAM是一个博大精深的算法.虽然没有像网络流家族,Tarjan家族一样拉帮结派,但是自身包含很多方法. 一.前言 字符串常见问题:各种匹配 1.L ...
- 学习笔记:平衡树-splay
嗯好的今天我们来谈谈cosplay splay是一种操作,是一种调整二叉排序树的操作,但是它并不会时时刻刻保持一个平衡,因为它会根据每一次操作把需要操作的点旋转到根节点上 所谓二叉排序树,就是满足对树 ...
- 平衡树(splay)学习笔记(详细,从入门到精(bao)通(ling))(持续更新)
前言 在前几天军训站军姿的时候胡思乱想,突然明白了splay的本质 KMP学习笔记后又一篇字数上万的题解- 前置技能--二叉搜索树 首先来看一个最简单的问题: 你需要维护一个数据结构,资磁这些操作: ...
- 平衡树 - FHQ 学习笔记
平衡树 - FHQ 学习笔记 主要参考万万没想到 的 FHQ-Treap学习笔记. 本片文章的姊妹篇:平衡树 - Splay 学习笔记. 感觉完全不会平衡树,又重新学习了一遍 FHQ,一口气把常见套路 ...
- 平衡树学习笔记之 fhq Treap
平衡树学习笔记 1:fhq Treap(非旋 Treap) 正文开始前首先 %%% fhq 大佬. 众所周知,平衡树是一种 非常猥琐 码量堪忧的数据结构. 他的祖先是一种叫做二叉搜索树 ( B S T ...
- pbds库学习笔记(优先队列、平衡树、哈希表)
目录 pbds库学习笔记(优先队列.平衡树.哈希表) 前言 概述 priority_queue优先队列 概述 参数 堆的基本操作的函数 对比STL新增函数 modify修改 Dijkstra最短路径演 ...
- Treap平衡树学习笔记
Treap平衡树学习笔记 放在前面的话 与信息学竞赛告别9个月后,中考终于结束,我终于复出了... 结果一回来就学数据结构,学得我有点懵... 本文写了两个多星期... 尽管学习Treap感到万分痛苦 ...
- [学习笔记]可持久化数据结构——数组、并查集、平衡树、Trie树
可持久化:支持查询历史版本和在历史版本上修改 可持久化数组 主席树做即可. [模板]可持久化数组(可持久化线段树/平衡树) 可持久化并查集 可持久化并查集 主席树做即可. 要按秩合并.(路径压缩每次建 ...
最新文章
- [C++对象模型][6]sizeof与对象内存布局
- KDD2020接受论文列表已公开!338篇优秀论文汇总!
- HDLBits 系列(31)Serial Receiver and Datapath
- union(联合)合并查询结果
- .java生成dex文件
- 企业CIO如何让IT部门成为价值中心
- 深入理解缓存系统|单机QPS突破千万优化之路
- 解决方案:分布式ID生成
- 油画作品欣赏|奥地利艺术家克里姆特
- C语言之预处理探究(四):#、##和预定义宏
- [补档]noip2019集训测试赛(十二)
- arcgis engine设置数据源路径_不用ArcGIS做前期分析,你是不是想被辞!
- 【C++】 ArcFace Demo2.0版
- 如何制作毕业地图分布图_最简单的数据地图制作,一共6步搞定!
- PHP连接MySQL 8.0报错的解决办法
- 数字技术加持 华为云为测绘地理信息产业夯实“云底座”
- Redis HyperLogLog 是什么?这些场景使用它,让我枪出如龙,一笑破苍穹
- MongoDB的用户管理总结
- Sun Solaris系统管理命令简介
- SPP中Supersession与Item Sourcing Rule的关系
热门文章
- React入门基础+练习(二)
- A5如何备份oracle数据库,oracle的数据库的导入导出
- JSP中9个隐含对象
- 数据库设计:范式与反范式
- PLSQL 连接不上
- 安卓 java 视频_安卓实战项目-动态桌面-rxjava实现搜索本地所有视频
- 【LOJ101】最大流(Dinic)
- java运行提示runtime,Java 执行运行时命令 Runtime
- oracle model类型,Oracle SQL高级编程——Model子句全解析-Oracle
- MyBatis→优缺点、select延迟加载、接口式MyBatis编程、一级缓存、二级缓存、集成Redis自定义缓存、Log4j