BZOJ5084 hashit
hashit
你有一个字符串S,一开始为空串,要求支持两种操作:
- 在S后面加入字母C。
- 删除S最后一个字母。
问每次操作后S有多少个两两不同的连续子串。
|Q|<=105
题解
https://blog.csdn.net/qq_36797743/article/details/78841291
很明显,题目给你的是一个字典树。你可以dfs下去,顺便建立SAM。
然后在回溯的时候将SAM还原,就可以O(n)(?)地解决这个问题了
我思忖后缀自动机怎么个还原法。原来是直接记录修改操作……学习了
但是这个谁都看得出来复杂度不对……
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100005;
char str[N];
int len;
int now,tot,last;
struct trie {
int ch[26],fa,c;//他自己是什么字符
} o[N];
void build_tree () {
now=0,tot=0;
for (int u=0; u<len; u++) {
if (str[u]=='-') now=o[now].fa;
else {
int x=str[u]-'a';
if (o[now].ch[x]==0) {
o[now].ch[x]=++tot,o[tot].c=x,o[tot].fa=now;
}
now=o[now].ch[x];
}
}
}
struct sam {
int ch[26],len,fa;
} s[N<<2];
int res=0;//现在有多少个不同的串了
struct operation {
int x,y,z;
int op;//什么类型
} sta[N<<2]; //撤销操作
int num=0;//当前撤销到哪里
void extend (int x) { //插入这个新的点
int p=last,np=++tot;
s[np].len=s[p].len+1;
while (p!=0&&s[p].ch[x]==0) {
/**/
num++;
sta[num].x=p,sta[num].y=x,sta[num].z=s[p].ch[x],sta[num].op=0;
/**/
s[p].ch[x]=np,p=s[p].fa;
}
if (p==0) s[np].fa=1;
else {
int q=s[p].ch[x];
if (s[p].len+1==s[q].len) s[np].fa=q;
else {
int nq=++tot;
s[nq]=s[q],s[nq].len=s[p].len+1;
/**/
num++;
sta[num].x=q,sta[num].y=s[q].fa,sta[num].op=1;
/**/
s[q].fa=s[np].fa=nq;
while (p!=0&&s[p].ch[x]==q) {
/**/
num++,sta[num].x=p,sta[num].y=x,sta[num].z=s[p].ch[x],sta[num].op=0;
/**/
s[p].ch[x]=nq,p=s[p].fa;
}
}
}
res=res+s[np].len-s[s[np].fa].len;
last=np;
}
int ans[N];//每个节点的答案
void dfs (int x) {
int old_num=num,old_res=res,ooo=last;
extend(o[x].c);
ans[x]=res;
for (int u=0; u<26; u++)
if (o[x].ch[u]!=0)
dfs(o[x].ch[u]);
for (int u=old_num+1; u<=num; u++) { //撤销操作
int x=sta[u].x,y=sta[u].y,z=sta[u].z;
if (sta[u].op==0)//ch的修改
s[x].ch[y]=z;
if (sta[u].op==1)//fa的修改
s[x].fa=y;
}
res=old_res,last=old_last,num=old_num;
}
void solve () {
tot=1;
for (int u=0; u<26; u++)
if (o[0].ch[u]!=0) {
s[1].len=0,s[1].fa=0;
for (int i=0; i<26; i++) s[1].ch[i]=0;
last=1,res=0;
dfs(o[0].ch[u]);
}
now=0;
for (int u=0; u<len; u++) {
if (str[u]=='-') now=o[now].fa;
else {
int x=str[u]-'a';
now=o[now].ch[x];
}
printf("%d\n",ans[now]);
}
}
int main() {
scanf("%s",str),len=strlen(str);
build_tree(),solve();
return 0;
}
静渊以有谋,疏通而知事。
浙公网安备 33010602011771号