后缀数组+平衡树=后缀平衡树

支持动态插入字符(只能往前插入),即插入一个后缀,维护所有后缀的排名

插入后缀找到位置?平衡树上二分

法一:

哈希+二分,太慢

法二:

第一个字符不同,已经可以比较,否则比较第二个字符开始的后缀,之前这两个后缀排名已经处理好了。直接比较排名即可。

查询任意位置的排名?

法一:

暴力这个点往上跳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

[学习笔记]后缀平衡树相关推荐

  1. [学习笔记]后缀数组

    参考: 后缀数组 最详细讲解 上面一篇是转载这一篇的: 后缀数组 学习笔记 一. 后缀:suff(i),后缀要排序 sa[i],排名为i的后缀开始位置 rk[i],i开始位置的后缀的排名. rk[sa ...

  2. [学习笔记]后缀自动机

    解决大部分字符串问题的大杀器 给一下clj课件:戳我 SAM是一个博大精深的算法.虽然没有像网络流家族,Tarjan家族一样拉帮结派,但是自身包含很多方法. 一.前言 字符串常见问题:各种匹配 1.L ...

  3. 学习笔记:平衡树-splay

    嗯好的今天我们来谈谈cosplay splay是一种操作,是一种调整二叉排序树的操作,但是它并不会时时刻刻保持一个平衡,因为它会根据每一次操作把需要操作的点旋转到根节点上 所谓二叉排序树,就是满足对树 ...

  4. 平衡树(splay)学习笔记(详细,从入门到精(bao)通(ling))(持续更新)

    前言 在前几天军训站军姿的时候胡思乱想,突然明白了splay的本质 KMP学习笔记后又一篇字数上万的题解- 前置技能--二叉搜索树 首先来看一个最简单的问题: 你需要维护一个数据结构,资磁这些操作: ...

  5. 平衡树 - FHQ 学习笔记

    平衡树 - FHQ 学习笔记 主要参考万万没想到 的 FHQ-Treap学习笔记. 本片文章的姊妹篇:平衡树 - Splay 学习笔记. 感觉完全不会平衡树,又重新学习了一遍 FHQ,一口气把常见套路 ...

  6. 平衡树学习笔记之 fhq Treap

    平衡树学习笔记 1:fhq Treap(非旋 Treap) 正文开始前首先 %%% fhq 大佬. 众所周知,平衡树是一种 非常猥琐 码量堪忧的数据结构. 他的祖先是一种叫做二叉搜索树 ( B S T ...

  7. pbds库学习笔记(优先队列、平衡树、哈希表)

    目录 pbds库学习笔记(优先队列.平衡树.哈希表) 前言 概述 priority_queue优先队列 概述 参数 堆的基本操作的函数 对比STL新增函数 modify修改 Dijkstra最短路径演 ...

  8. Treap平衡树学习笔记

    Treap平衡树学习笔记 放在前面的话 与信息学竞赛告别9个月后,中考终于结束,我终于复出了... 结果一回来就学数据结构,学得我有点懵... 本文写了两个多星期... 尽管学习Treap感到万分痛苦 ...

  9. [学习笔记]可持久化数据结构——数组、并查集、平衡树、Trie树

    可持久化:支持查询历史版本和在历史版本上修改 可持久化数组 主席树做即可. [模板]可持久化数组(可持久化线段树/平衡树) 可持久化并查集 可持久化并查集 主席树做即可. 要按秩合并.(路径压缩每次建 ...

最新文章

  1. [C++对象模型][6]sizeof与对象内存布局
  2. KDD2020接受论文列表已公开!338篇优秀论文汇总!
  3. HDLBits 系列(31)Serial Receiver and Datapath
  4. union(联合)合并查询结果
  5. .java生成dex文件
  6. 企业CIO如何让IT部门成为价值中心
  7. 深入理解缓存系统|单机QPS突破千万优化之路
  8. 解决方案:分布式ID生成
  9. 油画作品欣赏|奥地利艺术家克里姆特
  10. C语言之预处理探究(四):#、##和预定义宏
  11. [补档]noip2019集训测试赛(十二)
  12. arcgis engine设置数据源路径_不用ArcGIS做前期分析,你是不是想被辞!
  13. 【C++】 ArcFace Demo2.0版
  14. 如何制作毕业地图分布图_最简单的数据地图制作,一共6步搞定!
  15. PHP连接MySQL 8.0报错的解决办法
  16. 数字技术加持 华为云为测绘地理信息产业夯实“云底座”
  17. Redis HyperLogLog 是什么?这些场景使用它,让我枪出如龙,一笑破苍穹
  18. MongoDB的用户管理总结
  19. Sun Solaris系统管理命令简介
  20. SPP中Supersession与Item Sourcing Rule的关系

热门文章

  1. React入门基础+练习(二)
  2. A5如何备份oracle数据库,oracle的数据库的导入导出
  3. JSP中9个隐含对象
  4. 数据库设计:范式与反范式
  5. PLSQL 连接不上
  6. 安卓 java 视频_安卓实战项目-动态桌面-rxjava实现搜索本地所有视频
  7. 【LOJ101】最大流(Dinic)
  8. java运行提示runtime,Java 执行运行时命令 Runtime
  9. oracle model类型,Oracle SQL高级编程——Model子句全解析-Oracle
  10. MyBatis→优缺点、select延迟加载、接口式MyBatis编程、一级缓存、二级缓存、集成Redis自定义缓存、Log4j