广义后缀自动机

同时处理多个字符串的字串问题

在线写法

const int N=1e6+10;
int len[2*N],link[2*N],tr[2*N][32],con=2,last=1;
int add(int c,int last)
{
    if(tr[last][c])
    {
        if(len[last]+1==len[tr[last][c]]) return tr[last][c];
        int ne=con++,p=last,r=tr[last][c];
        len[ne]=len[p]+1;
        link[ne]=link[r];
        link[r]=ne;
        memcpy(tr[ne],tr[r],sizeof(tr[ne]));
        while(p&&tr[p][c]==r)
        {
            tr[p][c]=ne;
            p=link[p];
        }
        return ne;
    }
    int now=con++,p;
    len[now]=len[last]+1;
    for(p=last;p&&!tr[p][c];p=link[p])
    tr[p][c]=now;
    last=now;
    if(!p)link[now]=1;
    else
    {
        int r=tr[p][c];
        if(len[r]==len[p]+1)link[now]=r;
        else
        {
            int ne=con++;
            len[ne]=len[p]+1;
            link[ne]=link[r];
            link[now]=link[r]=ne;
            memcpy(tr[ne],tr[r],sizeof(tr[ne]));
            while(p&&tr[p][c]==r)
            {
                tr[p][c]=ne;
                p=link[p];
            }
        }
    }
    return last;
}

  trie树离线写法求每个状态endpos大小

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int len[2*N],link[2*N],tr[2*N][32],con=2,deg[2*N],endpos[2*N],sta[N*2],par[2*N][32];
char s[N];
int h[N],to[N],nex[N],id=1;
void add(int a,int b)//trie树离线构造,求每个状态endpos大小
{
    nex[id]=h[a];
    h[a]=id;
    to[id++]=b;
}
int insert(int c,int last)//也可用于在线构造,每次插入一个模式串之前,要把 last 设为 1
{
   // cout<<c<<endl;
    if(tr[last][c])
    {
        if(len[last]+1==len[tr[last][c]]) {return tr[last][c];}
        int ne=con++,p=last,r=tr[last][c];
        len[ne]=len[p]+1;
        link[ne]=link[r];
        link[r]=ne;
        memcpy(tr[ne],tr[r],sizeof(tr[ne]));
        while(p&&tr[p][c]==r)
        {
            tr[p][c]=ne;
            p=link[p];
        }
        return ne;
    }
    int now=con++,p;
    len[now]=len[last]+1;
    for(p=last;p&&!tr[p][c];p=link[p])
    tr[p][c]=now;
    last=now;
    if(!p)link[now]=1;
    else
    {
        int r=tr[p][c];
        if(len[r]==len[p]+1)link[now]=r;
        else
        {
            int ne=con++;
            len[ne]=len[p]+1;
            link[ne]=link[r];
            link[now]=link[r]=ne;
            memcpy(tr[ne],tr[r],sizeof(tr[ne]));
            while(p&&tr[p][c]==r)
            {
                tr[p][c]=ne;
                p=link[p];
            }
        }
    }
    return last;
}
void bfs()
{
    queue<int>q;
    for(int i=1;i<con;++i)
    if(!deg[i])q.push(i);
    while(!q.empty())
    {
        int now=q.front();q.pop();
        deg[link[now]]--;
        endpos[link[now]]+=endpos[now];
        if(!deg[link[now]])
        {
            q.push(link[now]);
        }
    }
}
void build()
{
    queue<int>q;
    q.push(0);
    sta[0]=1;
    while(!q.empty())
    {
        int now=q.front();q.pop();
        for(int i=h[now];i;i=nex[i])
        {
        sta[to[i]]=insert(s[to[i]]-'A',sta[now]);
        endpos[sta[to[i]]]++;
        q.push(to[i]);
        }
    }
}
int main()
{
  //  freopen("1.txt","r",stdin);
    int n,q;
    cin>>n>>q;
    scanf("%s",s+1);
    add(0,1);
    for(int i=1;i<n;++i)
    {
        int x;scanf("%d",&x);
        add(x,i+1);
    }
    build();
    for(int i=1;i<con;++i)
    deg[link[i]]++;
    bfs();
    for(int i=1;i<con;++i)
    par[i][0]=link[i];
    for(int i=1;i<25;++i)//倍增跳link树
        for(int j=1;j<con;++j)
        par[j][i]=par[par[j][i-1]][i-1];
    while(q--)
    {
        int x,l;scanf("%d%d",&x,&l);//求trie树x结点向上长度为l的字符串出现次数
        x=sta[x];
        for(int i=24;i>=0;--i)
        {
            if(len[par[x][i]]>=l)
            x=par[x][i];
        }
        printf("%d\n",endpos[x]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值