bzoj 5084 hashit
LINK:hashit
动态在末尾删除一个节点或者加入一个节点 求每次操作过后本质不同的子串的个数。
显然我们可以离线,当然我们发现删除末尾的节点也是比较困难的 可以选择不删而是返回到last.
发现这样做其实是一颗trie树 我们建立广义SAM.
每次加入节点 其实是parent树上一堆链的并的答案。(不明白可以画一下样例的图即可。
我们将操作离线后使用常规set维护dfs序解决。
const int MAXN=200010;
int n,cnt=1,last=1,v,len;
struct wy
{
int fa,len;
int ch[26];
}t[MAXN];
int f[MAXN][20],d[MAXN],Log[MAXN],pre[MAXN],dfn[MAXN],pos[MAXN];
int lin[MAXN],ver[MAXN],nex[MAXN];
char a[MAXN];
set<int>s;
set<int>::iterator it;
inline void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
inline int insert(int x)
{
int p=last;
if(t[p].ch[x])
{
int q=t[p].ch[x];
if(len(q)==len(p)+1)return last=q;
int nq=++cnt;
t[nq]=t[q];
f(q)=nq;
len(nq)=len(p)+1;
while(p&&t[p].ch[x]==q)
{
t[p].ch[x]=nq;
p=f(p);
}
return last=nq;
}
int np=last=++cnt;
len(np)=len(p)+1;
while(p&&!t[p].ch[x])
{
t[p].ch[x]=np;
p=f(p);
}
if(!p)f(np)=1;
else
{
int q=t[p].ch[x];
if(len(q)==len(p)+1)f(np)=q;
else
{
int nq=++cnt;
t[nq]=t[q];
f(q)=f(np)=nq;
len(nq)=len(p)+1;
while(p&&t[p].ch[x]==q)
{
t[p].ch[x]=nq;
p=f(p);
}
}
}
return last;
}
inline void dfs(int x,int father)
{
f[x][0]=father;d[x]=d[father]+1;dfn[x]=++v;pos[v]=x;
rep(1,Log[d[x]],i)f[x][i]=f[f[x][i-1]][i-1];
go(x)dfs(tn,x);return;
}
inline int LCA(int x,int y)
{
if(d[x]<d[y])swap(x,y);
for(int i=Log[d[x]];i>=0;--i)
if(d[f[x][i]]>=d[y])x=f[x][i];
if(x==y)return x;
for(int i=Log[d[x]];i>=0;--i)
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
int main()
{
freopen("1.in","r",stdin);
gc(a);n=strlen(a+1);ll ans=0;
rep(1,n,i)
{
if(a[i]=='-')last=pre[last];
else
{
int w=last;
insert(a[i]-'a');pre[last]=w;
}
}
rep(2,cnt,i)add(f(i),i),Log[i]=Log[i>>1]+1;
dfs(1,0);int now=1;
for(int i=1;i<=n;++i)
{
if(a[i]=='-')
{
ans-=len(now);it=s.find(dfn[now]);
int x=0,y=0;++it;
if(it!=s.end())x=pos[*it];
--it;
if(it!=s.begin())y=pos[*--it];
if(x)ans+=len(LCA(x,now));
if(y)ans+=len(LCA(y,now));
if(x&&y)ans-=len(LCA(x,y));
s.erase(dfn[now]);now=pre[now];
}
else
{
now=t[now].ch[a[i]-'a'];ans+=len(now);
it=s.upper_bound(dfn[now]);
int x=0,y=0;
if(it!=s.end())y=pos[*it];
if(it!=s.begin())x=pos[*--it];
if(x)ans-=len(LCA(x,now));
if(y)ans-=len(LCA(y,now));
if(x&&y)ans+=len(LCA(x,y));
s.insert(dfn[now]);
}
put(ans);
}
return 0;
}