失配树

失配树

题意简述

\(s\)\(p\) 前缀 和 \(q\) 前缀 的 最长公共 \(border\) 的长度。

解法

  1. \(kmp\)\(s\)\(nxt\) 数组, 则S 的所有 \(border\)\(s_{1..nxt(|s|)},s_{1..nxt(nxt(|s|)),...,s_{1..nxt(..nxt(|s|))}\)
  2. 通过 \(nxt\) 数组建一棵树(\(fail\) 树)
  3. \(fail\) 树上求 \(LCA\)

code

求nxt数组+建树

il void getfail(){
    len=strlen(s+1);
    for(int i=2,j=0;i<=len;i++){
        while(j&&s[i]!=s[j+1]) j=f[j][0];
        if(s[i]==s[j+1]) j++;
        f[i][0]=j,dep[i]=dep[j]+1;
        for(ri int k=1;k<=21;++k){
            f[i][k]=f[f[i][k-1]][k-1];
        }
    }    
    return;
}
code
#include <bits/stdc++.h>
#define il inline
#define cs const
#define ri register
using namespace std;

namespace Q{
    il int rd(){
        ri int x=0;ri bool f=0;ri char c=getchar();
        while(!isdigit(c)) f|=(c==45),c=getchar();
        while(isdigit(c)) x=x*10+(c^48),c=getchar();
        return f?-x:x;
    }
    il void wt(int x){
        if(x<0) x=-x,putchar(45);
        if(x>=10) wt(x/10);
        return putchar(x%10|48),void();
    }
} using namespace Q;

cs int N=1e6+5;
char s[N];
int m,p,q,f[N][22],len,dep[N];

il void getfail(){
    len=strlen(s+1);
    for(int i=2,j=0;i<=len;i++){
        while(j&&s[i]!=s[j+1]) j=f[j][0];
        if(s[i]==s[j+1]) j++;
        f[i][0]=j,dep[i]=dep[j]+1;
        for(ri int k=1;k<=21;++k){
            f[i][k]=f[f[i][k-1]][k-1];
        }
    }    
    return;
}

il int lca(int a,int b){
    if(dep[a]<dep[b]) swap(a,b);
    for(ri int i=21;~i;--i){
        if(dep[f[a][i]]>=dep[b]) a=f[a][i];
    }
    for(ri int i=21;~i;--i){
        if(f[a][i]^f[b][i]) a=f[a][i],b=f[b][i];
    }
    return f[a][0];
}

signed main(){
    scanf("%s",s+1);//
    getfail(),m=rd();
    for(ri int i=1;i<=m;++i){
        p=rd(),q=rd();
        wt(lca(p,q)),putchar(10);
    }
    return 0;
}

edit

posted @ 2023-03-06 07:50  雨夜风月  阅读(42)  评论(0编辑  收藏  举报