本题特点:
支持前后端插入字符,在线询问回文子串或本质不同回文子串数。
我们要维护前后端插入,就要维护两个last。一个pre,一个suf。
将回文自动机判断字符相等的
s[i-t[last].len-1]==s[i]
改为
s[i-t[last].len*op-op]==s[i]
并在前端插入时将op设为-1即可。
注意:
初始将l设为1e5,r设为l-1。防止爆炸。
如果上一个回文串长度恰为已经插入的字符串长,说明这个串就是原串。需将pre和suf同时设为该点。
维护本质相同字符串只需使用tot-1
本质不同则虚拟使用fail树,父亲是孩子的子串,所以用dep即能表示回文串的子串数量。
代码
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
struct node{
int fa,ch[26],len,dep;
}t[500003];
int l,r,pre,suf,T;
char s[500003];
int tot,ans;
void insert(int x,int N,int &last,int op){
int p=last;
while(s[N]!=s[N-op*t[p].len-op])p=t[p].fa;
if(!t[p].ch[x]){
tot++;
int temp=t[p].fa;
while(s[N]!=s[N-op*t[temp].len-op])temp=t[temp].fa;
t[tot].fa=t[temp].ch[x];t[tot].len=t[p].len+2;
t[tot].dep=t[t[tot].fa].dep+1;t[p].ch[x]=tot;
}
last=t[p].ch[x];ans+=t[last].dep;if(t[last].len==r-l+1)pre=suf=last;
}
signed main(){
int q;
while(scanf("%lld",&q)!=EOF){
l=1e5,r=l-1;memset(t,0,sizeof(t));memset(s,0,sizeof(s));
t[0].fa=1;t[1].len=-1;t[1].fa=1;tot=1;ans=0;pre=suf=0;
int op;
while(q--){
op=in;
if(op<=2){
char c;scanf("%c",&c);
if(op==1)s[--l]=c,insert(c-97,l,pre,-1);
else s[++r]=c,insert(c-97,r,suf,1);
}
if(op==3)printf("%lld\n",tot-1);
if(op==4)printf("%lld\n",ans);
}
}
return 0;
}