「ICPC World Finals 2019」何以伊名始(广义后缀自动机)

题目链接

题解:
对输入的trie图建立SAM,然后将询问反转,这个串对应的点的endpos集合就是答案。
还挺水的(逃


AC代码:

#pragma GCC optimize(2)
#include
using namespace std;
const int MAXN = 2e6+50;
int trie[MAXN][26],nxt[MAXN][26],fa[MAXN],len[MAXN];
int id[MAXN],sz[MAXN],c[MAXN],a[MAXN],tot=1;
char s[MAXN];
inline int Insert(int x,int p){
    int np=++tot; len[np]=len[p]+1; sz[np]=1;
    for(;p && !nxt[p][x];p=fa[p]) nxt[p][x]=np;
    if(!p) fa[np]=1;
    else{
        int q=nxt[p][x];
        if(len[p]+1==len[q]) fa[np]=q;
        else{
            int nq=++tot;
            len[nq]=len[p]+1;
            memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
            fa[nq]=fa[q];
            fa[q]=fa[np]=nq;
            for(;nxt[p][x]==q;p=fa[p]) nxt[p][x]=nq;
        }
    }
    return np;
}
int main(){
    int n,Q; scanf("%d%d",&n,&Q);
    for(int i=1;i<=n;i++){
        char ch; int bel;
        scanf(" %c %d",&ch,&bel);
        trie[bel][ch-'A']=i;
    }
    queue<int> que;
    que.push(0); id[0]=1;
    while(!que.empty()){
        int u=que.front(); que.pop();
        for(int i=0;i<26;i++){
            if(trie[u][i]){
                que.push(trie[u][i]);
                id[trie[u][i]] = Insert(i,id[u]);
            }
        }
    }
    for(int i=1;i<=tot;i++) c[len[i]]++;
    for(int i=1;i<=tot;i++) c[i]+=c[i-1];
    for(int i=tot;i;i--) a[c[len[i]]--]=i;
    for(int i=tot;i;i--) sz[fa[a[i]]] += sz[a[i]];
    while(Q--){
        scanf("%s",s);
        int l=strlen(s),rt=1; bool ok=true;
        for(int i=l-1;i>=0;i--){
            if(!nxt[rt][s[i]-'A']) { ok=false;break; }
            rt=nxt[rt][s[i]-'A'];
        }
        printf("%d\n",ok ? sz[rt]:0);
    }
    return 0;
}

你可能感兴趣的:(广义后缀自动机)