【回文自动机】【hdu5421】Victor and String

叶子最可爱了

本题特点:

支持前后端插入字符,在线询问回文子串或本质不同回文子串数。

我们要维护前后端插入,就要维护两个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;
}

 

上一篇:刷题清单2-DP


下一篇:基本数据类型