LG5357 「模板」AC自动机(二次加强版) AC自动机+fail树

问题描述

LG5357


题解

不是fail树AC自动机复杂度是假的。

AC自动机搞出来,建立Trie树,树上爆搜一遍就好了。


\(\mathrm{Code}\)

#include<bits/stdc++.h>
using namespace std;

template <typename Tp>
void read(Tp &x){
    x=0;char ch=1;int fh;
    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
    if(ch=='-') ch=getchar(),fh=-1;
    else fh=1;
    while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    x*=fh;
}

int root,ch[200007][26],tot,n;
char s[2000003];

int pos[200007],val[200007],fail[200007];
int m,ed[200007];

int chk(char s){
    return s-'a';
}

void insert(int x){
    int p=root;
    for(int i=1;i<=n;i++){
        int k=chk(s[i]);
        if(!ch[p][k]) ch[p][k]=++tot;
        p=ch[p][k];
    }
    ++ed[p],pos[x]=p;
}

void query(){
    int p=root;
    for(int i=1;i<=n;i++){
        p=ch[p][chk(s[i])];
        ++val[p];
    }
}

void build(){
    queue<int>q;
    for(int i=0;i<26;i++){
        if(ch[root][i]) q.push(ch[root][i]);
    }
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=0;i<26;i++){
            if(ch[x][i]) fail[ch[x][i]]=ch[fail[x]][i],q.push(ch[x][i]);
            else ch[x][i]=ch[fail[x]][i];
        }
    }
}

int Head[200007],Next[200007],cnt,to[200007];

void add(int x,int y){
    to[++cnt]=y,Next[cnt]=Head[x],Head[x]=cnt;
}

int size[200007];

void dfs(int x){
    size[x]=val[x];
    for(int i=Head[x];i;i=Next[i]){
        dfs(to[i]);size[x]+=size[to[i]];
    }
}

int main(){
    ios::sync_with_stdio(0);
    cin>>m;
    for(int i=1;i<=m;i++){
        cin>>(s+1);n=strlen(s+1);
        insert(i);
    }
    cin>>(s+1);n=strlen(s+1);
    build();query();
    for(int i=1;i<=tot;i++) add(fail[i],i);
    dfs(root);
    for(int i=1;i<=m;i++) cout<<size[pos[i]]<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/liubainian/p/11623311.html

时间: 2024-07-29 03:33:10

LG5357 「模板」AC自动机(二次加强版) AC自动机+fail树的相关文章

「模板」 FHQ_Treap

「模板」 FHQ_Treap <题目链接> 我也是偶然发现我还没发过FHQ_Treap的板子. 那就发一波吧. 这个速度实在不算快,但是不用旋转,并且好写. 更重要的是,Splay 可以做的事情它都可以做!比如区间操作,以及LCT相关- 而且它还可以可持久化!(虽然目前还没有学) Capella 认为,不涉及区间操作时,用快一些的平衡树(SBT/Treap/替罪羊...)较好,涉及区间操作而又不想写大量代码的话,FHQ_Treap 不失为一种极好的选择. 下一篇写 FHQ_Treap 的区间操

「模板」 割点

「模板」 割点 <题目链接> 不会点双导致的 APIO 完挂. 本应该联赛前学的东西,不及时学,就只有等到变回联赛选手后再学了吧. 以及,以后放弃链式前向星,存图一律指针邻接表. #include <algorithm> #include <cstdio> using std::min; const int MAXN=100010; bool cut[MAXN]; int n,m,DFN_num,ans,DFN[MAXN],low[MAXN]; struct Edge

「模板」 树套树

「模板」 树套树 <题目链接> 线段树套 SBT. 有生以来写过的最长代码. 虽然能过,但我删除 SBT 点的时候没回收内存!写了就 RE! 先放上来吧,回收内存调出来了再修改qwq. #include <algorithm> #include <climits> #include <cstdio> using std::max; using std::min; const int MAXN=50010; int n,m; class SegmentTree

「模板」 线段树——区间乘 &amp;&amp; 区间加 &amp;&amp; 区间求和

「模板」 线段树--区间乘 && 区间加 && 区间求和 <题目链接> 原来的代码太恶心了,重贴一遍. #include <cstdio> int n,m; long long p; class SegmentTree { private: struct Node { int l,r; long long v,mul,add; Node *c[2]; Node(int l,int r):l(l),r(r),mul(1LL),add(0LL) { c[

「模板」AC自动机(ACAM)

#include <algorithm> #include <cstdio> #include <cstring> #include <queue> using namespace std; const int MAXN=160,MAXM=11000,MAXL=1000010; char str[MAXN][80],p[MAXL]; int n; class ACAM { public: void Init(void) { tot=0; memset(cnt

「模板」线段树静态开点(单点+区间修改)、动态开点

相关讲解资料: 树状数组:https://blog.csdn.net/qq_34374664/article/details/52787481 (线段树预备) 线段树讲解: 初学版:https://blog.csdn.net/zearot/article/details/52280189 进阶完整版:https://www.cnblogs.com/AC-King/p/7789013.html 代码: 完整注释模板一张,参(chao)考(xi)楼上的博客 #include<iostream> #

「模板」 01 Trie实现平衡树功能

不想多说什么了.费空间,也不算太快,唯一的好处就是好写吧. #include <cstdio> #include <cstring> const int MAXN=100010<<5,INF=10000000; int n; class Trie { public: Trie(void) { cnt=1; memset(s,0,sizeof s); } void Insert(int x) { int k=1,p=x+INF; for(int i=30,t;~i;++s

LG5367 「模板」康托展开 康托展开

问题描述 LG5367 题解 康托展开公式: \[ans=1+(\sum_{i=1}^{n}{a_i})\times(n-i)!\] 用树状数组维护一下\(\sum\)里面的东西,前缀积维护后面的东西. \(\mathrm{Code}\) #include<bits/stdc++.h> using namespace std; template <typename Tp> void read(Tp &x){ x=0;char ch=1;int fh; while(ch!='

LG3812 「模板」线性基 线性基

问题描述 LG3812 题解 线性基是一类擅长解决异或问题的数据结构(也不算数据结构吧...就是一种玄学的东西) 对于数列 \(a\) ,它的线性基 \(d\) 为 出现 \(1\) 的最高位在第 \(i\) 位的数 (这里借用了"帅到报警"的题解). 构造方法 对于每一个尝试插入的数 \(x\) ,找出它目前为 \(1\) 的最高位 \(pos\) . 如果这个时候 \(d_pos\) 已经有了一个数,那么就把 \(x\) 异或上 \(d_pos\) 继续尝试. 否则插入,插入成功后