trie树上的回文自动机

本博客只是论文的一小部分。

这个应该算pam最基础的扩展了。例题hdu5394

直接暴力插入的复杂度肯定是不对的,是n^2的,我们需要优化找fail那个函数。

也就是说,我们要优化这样的操作,对于pam上的一个节点x,找到最长的前驱为c的回文后缀。

特判第一步就找到的情况。否则这个前驱字符一定在x内,可以预处理。每次新插入的点继承他fail的数组。

更具体的细节可以看代码。(也没有细节了)

#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<ctime>
#include<iostream>
#include<vector>
#include<cassert>
#include<algorithm>
#include<utility>
#include<queue>
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;
#define forg(i,x) for(register int i=fir[x];i;i=nxt[i])
#define uu unsigned
#define scanf a14=scanf
#define rint register int
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
typedef long long ll;
typedef uu long long ull;
typedef pair<int,int> pii;
int a14;
inline int rd(int l,int r){return rand()%(r-l+1)+l;}

const int mxn=2e6+5;
int len[mxn],fail[mxn],ts[mxn][4],tt,po[mxn],n,co[mxn],cnt[mxn],ju[mxn][4];
vector<int>g[mxn];
int s[mxn];

inline int gf(int x,int i){if(s[i]==s[i-len[x]-1])return x; return ju[x][s[i]];}
inline int ext(int id,int c,int n){
    int x=gf(id,n);
    if(!ts[x][c]){
        ++tt,len[tt]=len[x]+2;
        int y=ts[gf(fail[x],n)][c];if(!y)y=1;
        fail[tt]=y;
        ju[tt][0]=ju[y][0],ju[tt][1]=ju[y][1],ju[tt][2]=ju[y][2],ju[tt][3]=ju[y][3]; 
        ju[tt][s[n-len[y]]]=y;
        ts[x][c]=tt;
    }
    return ts[x][c];
}

inline void dfs(int x=0,int f=0,int d=0){
    if(x)s[d]=co[x]-'a',po[x]=ext(po[f],s[d],d),++cnt[po[x]];
    for(int i=0;i<g[x].size();++i)dfs(g[x][i],x,d+1);
}
int main(){
    s[0]=666;
    int ca;scanf("%d",&ca);while(ca--){
        for(int i=0;i<=tt;++i)ts[i][0]=ts[i][1]=ts[i][2]=ts[i][3]=cnt[i]=0;
        for(int i=0;i<=n;++i)g[i].clear();
//        len[1]=-1,tt=1,fail[0]=fail[1]=1;
        len[0]=-1,tt=1;
        scanf("%d",&n);for(int i=1;i<=n;++i){
            char c[2];int x;scanf("%s%d",c,&x);co[i]=c[0];
            g[x].push_back(i);
        }
        dfs();
        ll ans=0;
        for(int i=tt;i>1;--i)cnt[fail[i]]+=cnt[i],ans+=1ll*cnt[i]*len[i];
        printf("%lld\n",ans);
    }
    return 0;
}

posted @ 2021-04-22 17:42  yugyppah656  阅读(155)  评论(0编辑  收藏  举报