[洛谷P5829] 失配树

题目大意

给定一长为 \(n(n\leq 10^6)\) 的字符串 \(s\),\(m(m\leq 5\times 10^5)\)次询问,每次询问它的两个前缀的最长公共 border。

题解

先跑一遍KMP求出\(fail\)数组,每个\(pos\)向\(fail[pos]\)连边,建出\(fail\)树,在\(fail\)树上求lca即为两个前缀的最长公共border。

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
using namespace std;

#define RG register int
#define LL long long

template<typename elemType>
inline void Read(elemType &T){
    elemType X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    T=(w?-X:X);
}

const int maxn=1000010;

struct Graph{
    struct edge{int Next,to;};
    edge G[maxn<<1];
    int head[maxn];
    int cnt;

    Graph():cnt(2){}
    void clear(int node_num=0){
        cnt=2;
        if(node_num==0) memset(head,0,sizeof(head));
        else fill(head,head+node_num+5,0);
    }
    void add_edge(int u,int v){
        G[cnt].to=v;
        G[cnt].Next=head[u];
        head[u]=cnt++;
    }
};

namespace KMP{
    int LenP=0,*Fail=NULL;
    char *P=NULL;
    inline void bind_kmp(char *_P,int *_Fail,int _len){
        P=_P;Fail=_Fail;
        LenP=_len;
    }
    inline void get_fail(){//求出Fail数组
        Fail[1]=0;
        for(RG i=2,pos=0;i<=LenP;++i){
            while(pos && (pos==LenP || P[i]!=P[pos+1])) pos=Fail[pos];
            if(P[i]==P[pos+1]) ++pos;
            Fail[i]=pos;
        }
    }
};

Graph G;
char s[maxn];
int Fail[maxn];
int N,M;

int Deep[1000010],Anc[1000010][20];

void DFS_Init(int u,int fa){
    Anc[u][0]=fa;
    for(int i=1;i<20;++i)
        Anc[u][i]=Anc[Anc[u][i-1]][i-1];
    for(int i=G.head[u];i;i=G.G[i].Next){
        int v=G.G[i].to;
        if(v==fa) continue;
        Deep[v]=Deep[u]+1;
        DFS_Init(v,u);
    }
    return;
}

int LCA(int u,int v){
    int Root=N+1;
    if(u==Root || v==Root) return Root;
    if(Deep[u]<Deep[v]) swap(u,v);
    for(RG i=19;i>=0;--i){
        if(Deep[Anc[u][i]]>=Deep[v])
            u=Anc[u][i];
    }
    if(u==v) return u;
    for(RG i=19;i>=0;--i){
        if(Anc[u][i]!=Anc[v][i]){
            u=Anc[u][i];
            v=Anc[v][i];
        }
    }
    return Anc[u][0];
}

int main(){
    scanf("%s",s+1);
    N=strlen(s+1);
    KMP::bind_kmp(s,Fail,N);
    KMP::get_fail();
    for(RG u=1;u<=N;++u){
        int v=Fail[u];
        if(v==0) v=N+1;
        G.add_edge(u,v);
        G.add_edge(v,u);
    }
    DFS_Init(N+1,0);
    Read(M);
    while(M--){
        int u,v;
        Read(u);Read(v);
        u=Fail[u];v=Fail[v]; 
        if(!u || !v) printf("0\n");
        else{
            int Ans=LCA(u,v);
            if(Ans==N+1) Ans=0;
            printf("%d\n",Ans);
        }
    }
    return 0;
}
上一篇:省选测试20


下一篇:省选测试15