【bzoj5084】 hashit(广义SAM+set)
题面
题解
后缀平衡树是个啥啊我不会啊……
那么我们来考虑一下\(SAM\)的做法好了
不难发现它的本义是要我们维护一棵\(trie\)树,并求出\(trie\)树上每一个节点到根的这段串的不同子串个数,而显然一个串的不同子串个数就是它的\(SAM\)上每一个节点的\(len[p]-len[fa[p]]\)之和
那么我们对这个\(trie\)建一个广义\(SAM\),这个\(SAM\)一定包含每一个路径的\(SAM\)
我们对每一个这棵\(trie\)上的每一个节点记录一个\(pos\),表示这个节点插入在\(SAM\)上的哪一个位置,然后把\(SAM\)的\(parent\)树记录一下\(dfs\)序
那么操作可以看做是在\(parent\)树上插入和删除节点,以插入为例,我们可以直接加上\(p\)到根节点的\(len\),但是这样有可能会算多,于是我们要减去\(p\)的前驱(以\(dfs\)序为顺序排列)和\(p\)的\(LCA\)的\(len\),以及和它的后继的\(LCA\)的\(len\)。但是这样可能又减多了,所以还需要加上它的前驱和后继的\(LCA\)的\(len\)
然后没有然后了
//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define IT set<int>::iterator
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(char *s){
R int len=0;R char ch;while(((ch=getc())>'z'||ch<'a')&&ch!='-');
for(s[++len]=ch;(ch=getc())>='a'&&ch<='z'||ch=='-';s[++len]=ch);
return s[len+1]='\0',len;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R ll x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+5;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
char t[N];int l[N],ch[N][26],fa[N],pos[N],st[N],dep[N],dfn[N],top[N],sz[N],son[N],rk[N];
int las=1,cnt=1,n,tim;set<int> s;ll res;
void ins(int c,int p=las){
if(ch[p][c]){
int q=ch[p][c];
if(l[q]==l[p]+1)las=q;
else{
int nq=las=++cnt;l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],4*26);
fa[nq]=fa[q],fa[q]=nq;
for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}else{
int np=las=++cnt;l[np]=l[p]+1;
for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
if(!p)fa[np]=1;
else{
int q=ch[p][c];
if(l[q]==l[p]+1)fa[np]=q;
else{
int nq=++cnt;l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],4*26);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}
}
}
void dfs1(int u){
sz[u]=1,dep[u]=dep[fa[u]]+1;
go(u){
dfs1(v),sz[u]+=sz[v];
sz[v]>sz[son[u]]?son[u]=v:0;
}
}
void dfs2(int u,int t){
top[u]=t,rk[dfn[u]=++tim]=u;
if(!son[u])return;
dfs2(son[u],t);
go(u)if(!top[v])dfs2(v,v);
}
int LCA(int u,int v){
while(top[u]!=top[v]){
dep[top[u]]<dep[top[v]]?(swap(u,v),0):0;
u=fa[top[u]];
}return dep[u]<dep[v]?u:v;
}
void update(int u,int op){
if(op==1)s.insert(u);
IT itl,itr,it;itl=itr=it=s.find(u);
res+=op*l[rk[u]];
if(itl!=s.begin())--itl,res-=op*l[LCA(rk[u],rk[*itl])];
if(itr!=--s.end())++itr,res-=op*l[LCA(rk[u],rk[*itr])];
if(itl!=it&&itr!=it)res+=op*l[LCA(rk[*itl],rk[*itr])];
if(op==-1)s.erase(u);
}
int main(){
// freopen("testdata.in","r",stdin);
n=read(t);
st[0]=1;
for(R int i=1,top=0;i<=n;++i)if(t[i]=='-')--top;
else las=st[top],ins(t[i]-'a'),pos[i]=st[++top]=las;
fp(i,2,cnt)add(fa[i],i);
dfs1(1),dfs2(1,1);
for(R int i=1,top=0;i<=n;++i){
if(t[i]=='-')update(dfn[pos[st[top--]]],-1);
else update(dfn[pos[st[++top]=i]],1);
print(res);
}
return Ot(),0;
}
深深地明白自己的弱小