题意:
一个串,资瓷末端插入,删除一个字符,求每次操作后本质不同的子串个数;
题解:
“可持久化”后缀自动机裸题,类似按zhi并查集的“可持久化”,复杂度
O(N)
当时考场上的神犇大多是这么A的;
作死写了一发替罪羊树搞的后缀平衡树,代码感觉不长,实际比较长。。。
hash比较版本
O(NLog2N)
#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define seed 123
#define ls ch[x][0]
#define rs ch[x][1]
using namespace std;
const int N=2e5+7;
typedef unsigned long long ll;
typedef double db;
const db alpha=0.6;
char s[N],c[N];
int n,now,ch[N][2],sz[N],rt=0,goat=0,stk[N],top;
ll ans=0;
ll H[N],pw[N],his[N];
ll getha(int l,int r){
return H[r] - pw[r-l+1]*H[l-1];
}
void up(int x){
sz[x]=sz[ls] + 1 + sz[rs];
}
int lcp(int x,int y){
int l=0,r=min(x,y);
while(l<r){
int mid=(l+r+1)>>1;
if(getha(x-mid+1,x) == getha(y-mid+1,y))l=mid;
else r=mid-1;
}
return l;
}
bool cmp(int x,int y){
int l=lcp(x,y);
if(l==x)return true;
if(l==y)return false;
if(c[x-l]<c[y-l])return true;
else return false;
}
void del(int& x,int goal){
if(x==goal){
if(!(ls*rs)){int cls=ls,crs=rs;ls=rs=0;x=cls+crs;return;}
else{
int who=ls;
for(;ch[who][1];who=ch[who][1]);
del(rt,who);
ch[who][0]=ls;
ch[who][1]=rs;
ls=rs=0;
x=who;
up(x);
}
}
else{
int op=cmp(x,goal);
if(!op)del(ls,goal);
else del(rs,goal);
up(x);
}
}
void ins(int& x){
if(!x){x=now,sz[x]=1;}
else{
int op=cmp(x,now);
if(!op)ins(ls);
else ins(rs);
up(x);
if(max(sz[ls],sz[rs]) > alpha*sz[x])goat=x;
}
}
void dfs(int x){
if(!x)return;
dfs(ls);
stk[++top]=x;
dfs(rs);
}
void dfs_2(int& x,int l,int r){
if(l>r){x=0;return;}
int mid=(l+r)>>1;
x=stk[mid];
dfs_2(ls,l,mid-1);
dfs_2(rs,mid+1,r);
up(x);
}
void build(int& x){
top=0;
dfs(x);
dfs_2(x,1,top);
}
void rebuild(int& x){
if(x==goat){build(x);}
else{
int op=cmp(x,goat);
if(!op)rebuild(ls);
else rebuild(rs);
up(x);
}
}
int rank(int x){
int cc=rt,res=0;
for(;;){
if(cc==x){res+=sz[ls];break;}
int op=cmp(cc,x);
if(op)res+=sz[ch[cc][0]] + 1,cc=ch[cc][1];
else cc=ch[cc][0];
}
return res+1;
}
int kth(int k){
int cc=rt;
for(;;){
if(!cc)return cc;
if(sz[ch[cc][0]] + 1 == k)return cc;
else if(sz[ch[cc][0]] >= k)cc=ch[cc][0];
else{
k-=sz[ch[cc][0]] + 1;
cc=ch[cc][1];
}
}
}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
pw[0]=1;rep(i,1,n)pw[i]=pw[i-1]*seed;
rep(i,1,n){
if(s[i]=='-'){
del(rt,now);
now--;
printf("%llu\n",(ans=his[now]));
}else{
c[++now]=s[i]-'a';
H[now]=seed*H[now-1]+c[now]+1;
ins(rt);
int rk;
rk=rank(now);
int fr=kth(rk-1);
int suf=kth(rk+1);
int mx=max(lcp(now,fr),lcp(now,suf));
his[now]=(ans+=(now-mx));
printf("%llu\n",his[now]);
}
if(goat)rebuild(rt),goat=0;
}
}
动态标号版本 O(NLogN)
#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define seed 123
#define ls ch[x][0]
#define rs ch[x][1]
using namespace std;
const int N=2e5+7;
typedef unsigned long long ll;
typedef double db;
const db alpha=0.6;
char s[N],c[N];
int n,now,ch[N][2],sz[N],rt=0,goat=0,stk[N],top;
ll ans=0;
ll H[N],pw[N],his[N];
db L[N],R[N],tag[N];
ll getha(int l,int r){
return H[r] - pw[r-l+1]*H[l-1];
}
void up(int x){
sz[x]=sz[ls] + 1 + sz[rs];
}
int lcp(int x,int y){
int l=0,r=min(x,y);
while(l<r){
int mid=(l+r+1)>>1;
if(getha(x-mid+1,x) == getha(y-mid+1,y))l=mid;
else r=mid-1;
}
return l;
}
bool cmp(int x,int y){
if(c[x]<c[y])return true;
else if(c[x]>c[y])return false;
else return tag[x-1] < tag[y-1];
}
void del(int& x,int goal){
if(x==goal){
if(!(ls*rs)){int cls=ls,crs=rs;ls=rs=L[x]=R[x]=0;x=cls+crs;return;}
else{
int who=ls;
for(;ch[who][1];who=ch[who][1]);
del(rt,who);
ch[who][0]=ls;
ch[who][1]=rs;
L[who]=L[x];
R[who]=R[x];
tag[who]=tag[x];
ls=rs=L[x]=R[x]=tag[x]=0;
x=who;
up(x);
}
}
else{
int op=cmp(x,goal);
if(!op)del(ls,goal);
else del(rs,goal);
up(x);
}
}
void ins(int& x,db dl,db dr){
if(!x){x=now,sz[x]=1;L[x]=dl,R[x]=dr,tag[x]=(dl+dr)/2;}
else{
dl=L[x],dr=R[x];
int op=cmp(x,now);
db dmid=(dl+dr)/2;
if(!op)ins(ls,dl,dmid);
else ins(rs,dmid,dr);
up(x);
if(max(sz[ls],sz[rs]) > alpha*sz[x])goat=x;
}
}
void dfs(int x){
if(!x)return;
dfs(ls);
stk[++top]=x;
dfs(rs);
}
void dfs_2(int& x,int l,int r,db dl,db dr){
if(l>r){x=0;return;}
int mid=(l+r)>>1;
db dmid=(dl+dr)/2;
x=stk[mid];
tag[x]=dmid;
L[x]=dl,R[x]=dr;
dfs_2(ls,l,mid-1,dl,dmid);
dfs_2(rs,mid+1,r,dmid,dr);
up(x);
}
void build(int& x,db& l,db& r){
top=0;
dfs(x);
dfs_2(x,1,top,l,r);
}
void rebuild(int& x){
if(x==goat){build(x,L[x],R[x]);}
else{
int op=cmp(x,goat);
if(!op)rebuild(ls);
else rebuild(rs);
up(x);
}
}
int rank(int x){
int cc=rt,res=0;
for(;;){
if(cc==x){res+=sz[ls];break;}
int op=cmp(cc,x);
if(op)res+=sz[ch[cc][0]] + 1,cc=ch[cc][1];
else cc=ch[cc][0];
}
return res+1;
}
int kth(int k){
int cc=rt;
for(;;){
if(!cc)return cc;
if(sz[ch[cc][0]] + 1 == k)return cc;
else if(sz[ch[cc][0]] >= k)cc=ch[cc][0];
else{
k-=sz[ch[cc][0]] + 1;
cc=ch[cc][1];
}
}
}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
pw[0]=1;rep(i,1,n)pw[i]=pw[i-1]*seed;
rep(i,1,n){
if(s[i]=='-'){
del(rt,now);
now--;
printf("%llu\n",(ans=his[now]));
}else{
c[++now]=s[i]-'a';
H[now]=seed*H[now-1]+c[now]+1;
ins(rt,0,(1<<30));
int rk;
rk=rank(now);
int fr=kth(rk-1);
int suf=kth(rk+1);
int mx=max(lcp(now,fr),lcp(now,suf));
his[now]=(ans+=(now-mx));
printf("%llu\n",his[now]);
}
if(goat)rebuild(rt),goat=0;
}
}