PreSuffix ZOJ-3995 (LCA ejecutándose en el árbol de fallas de los autómatas de CA)

Significado del título:
darle n cadenas.
Luego pregunte q veces, cada vez pidiendo el sufijo más largo de dos de las n cadenas de caracteres, de modo que este sufijo sea el prefijo de algunas de las n cadenas de caracteres. ¿Cuál es el prefijo de este sufijo?

Idea:
cree el árbol de errores después de crear el árbol del diccionario.
Cada nodo del árbol del diccionario representa un prefijo, y la posición señalada por el puntero de error representa el prefijo más largo que este prefijo puede coincidir en el árbol del diccionario, y satisfacer este prefijo más largo es su propio sufijo.

Luego, cada vez que pregunte dos puntos, puede encontrar su LCA directamente en el árbol de fallas, que corresponde al sufijo más largo de los dos puntos y es la cadena prefijada por otras cadenas.

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int maxn = 1e6 + 7;

struct Trie {
    
    
    int son[30],val,fail;
}t[maxn];

int n,cnt;
char s[maxn];

int pos[maxn];
int head[maxn],to[maxn],nex[maxn],d[maxn],fa[maxn][30];//fa[i][j]代表i点的第2^j个祖先
int tot;

void add(int x,int y)
{
    
    
    to[++tot] = y;
    nex[tot] = head[x];
    head[x] = tot;
}

void dfs(int x)
{
    
    
    for(int i = head[x];i;i = nex[i])
    {
    
    
        int v = to[i];
        if(!d[v + 1])
        {
    
    
            d[v + 1] = d[x + 1] + 1;
            fa[v + 1][0] = x + 1;
            dfs(v);
        }
    }
}

int lca(int x,int y)
{
    
    
    if(d[x] < d[y])swap(x,y);//保证x是最深的
    for(int i = 20;i >= 0;i--)
    {
    
    
        if(d[fa[x][i]] >= d[y])
            x = fa[x][i];//将x移到和y一样的深度
    }
    
    if(x == y)//x移到y了,那说明x就是xy祖先
        return x;
    for(int i = 20;i >= 0;i--)
    {
    
    
        if(fa[x][i] != fa[y][i])
        {
    
    
            x = fa[x][i];
            y = fa[y][i];//x,y一起上移
        }
    }
    return fa[x][0];//此时x和y已经在同一个节点下了,返回x的父节点即可。
}


void init() {
    
    
    for(int i = 0;i <= cnt;i++) {
    
    
        memset(t[i].son,0,sizeof(t[i].son));
        t[i].val = t[i].fail = 0;
    }
    memset(pos,0,sizeof(pos));
    memset(d,0,sizeof(d));
    memset(fa,0,sizeof(fa));
    memset(head,0,sizeof(head));
    tot = 0;
    cnt = 0;
}

void insert(int id,char *s) {
    
    
    int u = 0,len = strlen(s);
    for(int i = 0;i < len;i++) {
    
    
        int v = s[i] - 'a';
        if(!t[u].son[v]) t[u].son[v] = ++cnt;
        u = t[u].son[v];
        t[u].val++;
    }
    pos[id] = u;
}

void getFail() {
    
    
    queue<int>q;
    q.push(0);t[0].fail = 0;
    while(!q.empty()) {
    
    
        int u = q.front();q.pop();
        for(int i = 0;i < 26;i++) {
    
    
            int v = t[u].son[i];
            int Fail = t[u].fail;
            if(!v) {
    
    
                t[u].son[i] = t[Fail].son[i];continue; //直接让不存在的儿子指向失配位置
            }
            if(Fail == 0 && t[Fail].son[i] == v) t[v].fail = 0;
            else t[v].fail = t[Fail].son[i];
            q.push(v);
        }
    }
}

int query(int x,int y) {
    
    
    x = pos[x] + 1;y = pos[y] + 1;
    int z = lca(x,y) - 1;
    return t[z].val;
}

int main() {
    
    
    int n;
    while(~scanf("%d",&n)) {
    
    
        init();
        for(int i = 1;i <= n;i++) {
    
    
            scanf("%s",s);
            insert(i,s);
        }
        getFail();
        for(int i = 1;i <= cnt;i++) {
    
    
            add(t[i].fail,i);
        }
        
        d[1] = 1;
        fa[1][0] = 0;
        dfs(0);
        for(int i = 1;i <= 20;i++)
        {
    
    
            for(int j = 1;j <= cnt;j++)
            {
    
    
                fa[j][i] = fa[fa[j][i - 1]][i - 1];//j的2^i次方祖先等于j的2^i-1次方祖先的2^i-1次方祖先。
            }
        }
        
        int m;scanf("%d",&m);
        while(m--) {
    
    
            int x,y;scanf("%d%d",&x,&y);
            int ans = query(x,y);
            if(!ans) printf("N\n");
            else printf("%d\n",ans);
        }
    }
    return 0;
}


Supongo que te gusta

Origin blog.csdn.net/tomjobs/article/details/109063059
Recomendado
Clasificación