【BZOJ4327】【JSOI2012】玄武密码 (fail树)

fail树(ac自动机)模板题

题意:

题目传送门

给出一个主串和一坨模式串,对于每个模式串,求能与主串匹配的最大子串长度

把那一坨串建好fail树,用主串在树上跑,在能匹配的地方打个标记

统计时从模式串底端向上跑,找到最长能被匹配的位置即可

代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ull unsigned long long
#define ll long long
#define inf 100009
#define infm 100*inf
#define INF (int)1e9
#define mod (INF+7)
#define rd(n) {n=0;char ch;int f=0;do{ch=getchar();if(ch=='-'){f=1;}}while(ch<'0'||ch>'9');while('0'<=ch&&ch<='9'){n=(n<<1)+(n<<3)+ch-48;ch=getchar();}if(f)n=-n;}
using namespace std;
 
struct trie{
    int son[4];
    int nxt;//fail标记
    int vis;//匹配标记
    int fa;
}t[infm];
int tcnt,root;
 
int Len[inf],pos[inf];
 
int newtree(int f){
    tcnt++;
    for (int i=0;i<26;i++){
        t[tcnt].son[i]=-1;
    }
    t[tcnt].nxt=-1;
    t[tcnt].vis=0;
    t[tcnt].fa=f;
    return tcnt;
}
 
int get(char s){//hash
    if (s=='E'){
        return 0;
    }
    if (s=='W'){
        return 1;
    }
    if (s=='S'){
        return 3;
    }
    if (s=='N'){
        return 2;
    }
}
 
void add(char s[],int id){
    int u=root;
    Len[id]=strlen(s);//不用记录整个字符串,只用记录len
    for (int i=0;i q;
void ac_build(void){//自认为打得挺好看的建树
    while (!q.empty()){
        q.pop();
    }
    q.push(root);
    t[root].nxt=root;
    while (!q.empty()){
        int u=q.front(),p;
        q.pop();
        for (int i=0;i<4;i++){
            if (u==root){
                p=root;
            }
            else{
                p=t[t[u].nxt].son[i];
            }
            if (t[u].son[i]<0){
                t[u].son[i]=p;
            }
            else{
                t[t[u].son[i]].nxt=p;
                q.push(t[u].son[i]);
            }
        }
    }
    return;
}
 
int cnt[inf];
void query(char s[]){
    int len=strlen(s);
    int u=root,v;//u:当前节点,v:用来跳fail的指针
    for (int i=0;i

 

你可能感兴趣的:(ac自动机)