后缀平衡树
继续搞点字符串。后缀平衡树。
后缀平衡树,就是后缀数组上平衡树。它的中序遍历是后缀数组。
但是它可以在线 \(O(n\log n)\) 构建,虽然码量大点。
当然你可以先把后缀数组求出来再建平衡树,但是这就没意义了。
显然我们每次插入删除字符的时候一定要在整个串最前面插入删除。也就是维护一大堆后缀。平衡树的每个节点就是一个后缀。
每次插入删除的复杂度平静在于比较两个后缀的大小。暴力比较是T飞的。观察到一个性质(以插入为例):新插入的后缀一定是形如 \(cS\) (\(c\) 是字符,\(S\) 是在平衡树里的一个后缀)。那么可以直接比较第一个字符,如果不同直接出。如果相同,就可以比较剩下的后缀,这个可以通过给每个后缀赋值代表大小关系来做到。
下面是一份基于替罪羊树实现的板子。板子很简单,查一个字符只要查有多少小于等于的后缀和小于的后缀减一下就行了。顺带一提后缀平衡树只要平衡树可持久化那它就可持久化。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson tree[x].son[0]
#define rson tree[x].son[1]
using namespace std;
const double mx=1e16;
int n,m;
char s[2000010],str[2000010];
struct node{
int son[2],size;
double tag;
}tree[2000010];
int rt,a[2000010];
bool cmp(int x,int y){
return s[x]<s[y]||(s[x]==s[y]&&tree[x-1].tag<tree[y-1].tag);
}
void pushup(int x){
tree[x].size=tree[lson].size+tree[rson].size+1;
}
void dfs(int x){
if(!x)return;
dfs(lson);
a[++a[0]]=x;
dfs(rson);
lson=rson=0;
}
void build(int &x,int L,int R,double l,double r){
if(L>R)return;
int mid=(L+R)>>1;
double Mid=(l+r)/2;
x=a[mid];tree[x].tag=Mid;
build(lson,L,mid-1,l,Mid);
build(rson,mid+1,R,Mid,r);
pushup(x);
}
bool judge(int x){
return 1.0*max(tree[lson].size,tree[rson].size)>0.7*tree[x].size;
}
void found(int &x,double l,double r){
a[0]=0;
dfs(x);
build(x,1,a[0],l,r);
}
void ins(int &x,int pos,double l,double r){
if(!x){
x=pos;tree[x].size=1;
tree[x].tag=(l+r)/2;
lson=rson=0;
return;
}
if(cmp(pos,x))ins(lson,pos,l,tree[x].tag);
else ins(rson,pos,tree[x].tag,r);
pushup(x);
if(judge(x))found(x,l,r);
}
void del(int &x,int pos){
if(x==pos){
if(!lson||!rson)x=lson|rson;
else{
int y=lson,tmp=x;
while(tree[y].son[1]){
tmp=y;
tree[tmp].size--;
y=tree[y].son[1];
}
if(tmp==x){
tree[y].son[1]=tree[x].son[1];
x=y;
pushup(x);
}
else{
tree[y].son[0]=tree[x].son[0];
tree[y].son[1]=tree[x].son[1];
tree[tmp].son[1]=0;
x=y;
pushup(x);
}
}
return;
}
if(cmp(pos,x))del(lson,pos);
else del(rson,pos);
pushup(x);
}
bool com(int x){
for(int p=1;str[p];p++,x=(x?x-1:0)){
if(str[p]<s[x])return true;
else if(str[p]>s[x])return false;
}
return false;
}
int query(int x){
if(!x)return 0;
if(com(x))return query(lson);
else return tree[lson].size+1+query(rson);
}
void decode(char s[],int mask){
int len=strlen(s);
for(int i=0;i<len;i++){
mask=(mask*131+i)%len;
swap(s[i],s[mask]);
}
}
int mask,ans;
int main(){
scanf("%d%s",&m,s+1);n=strlen(s+1);
for(int i=1;i<=n;i++)ins(rt,i,0,mx);
while(m--){
char od[10];scanf("%s",od);
if(od[0]=='A'){
scanf("%s",str+1);
decode(str+1,mask);
int len=strlen(str+1);
for(int j=1;j<=len;j++){
s[n+j]=str[j];ins(rt,n+j,0,mx);
}
n+=len;
}
else if(od[0]=='Q'){
scanf("%s",str+1);
decode(str+1,mask);
int len=strlen(str+1);
reverse(str+1,str+len+1);
str[len+1]='Z'+1;str[len+2]=0;
ans=query(rt);
str[len]--;
ans-=query(rt);
printf("%d\n",ans);
mask^=ans;
}
else{
int k;scanf("%d",&k);
for(int j=n;j>n-k;j--)del(rt,j);
n-=k;
}
}
return 0;
}
应用不知道。
快踩