ACM模板
目录
- 插入以及构建AC自动机
- 【模板】AC自动机(二次加强版)
- ac自动机fail树上dfs序建可持久化线段树
插入以及构建AC自动机
#include<queue>
#include<string>
const int N=200010;
struct node
{int chd[26],fail,cnt;
}tree[N];
void insert(string s)
{int p=0;for(int i=0;i<s.size();i++){int c=s[i]-'a';if(!tree[p].chd[c]) tree[p].chd[c]=++cnt;p=tree[p].chd[c];}
}
void build()
{queue<int> q;for(int i=0;i<26;i++)if(tree[0].chd[i]) q.push(tree[0].chd[i]);while(q.size()){int t=q.front();q.pop();for(int i=0;i<26;i++){int &chd=tree[t].chd[i];if(chd)tree[chd].fail=tree[tree[t].fail].chd[i],q.push(chd);else// 如果没有儿子 那么将fail的儿子作为儿子chd=tree[tree[t].fail].chd[i];}}
}
【模板】AC自动机(二次加强版)
给你一个文本串 SSS 和 nnn 个模式串 T1..nT_{1..n}T1..n,请你分别求出每个模式串 TiT_iTi 在 SSS 中出现的次数。
#include<queue>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
const int N=200010;
struct node
{int chd[26],fail,cnt;
}tree[N];
int cnt;
int h[N],e[N],ne[N],idx;
int pos[N];
void add(int a,int b)
{e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int insert(string s)
{int p=0;for(int i=0;i<s.size();i++){int c=s[i]-'a';if(!tree[p].chd[c]) tree[p].chd[c]=++cnt;p=tree[p].chd[c];}return p;
}
void build()
{queue<int> q;for(int i=0;i<26;i++){int c=tree[0].chd[i];if(!c) continue;tree[c].fail=0;add(0,c);q.push(c);}while(q.size()){int t=q.front();q.pop();for(int i=0;i<26;i++){int &chd=tree[t].chd[i];if(chd){tree[chd].fail=tree[tree[t].fail].chd[i];add(tree[chd].fail,chd);// 构建失配树 fail指针向自己连边q.push(chd);}elsechd=tree[tree[t].fail].chd[i];}}
}
void dfs(int u)
{for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];dfs(j);tree[u].cnt+=tree[j].cnt;}
}
int main()
{ios::sync_with_stdio(0);memset(h,-1,sizeof h);int n;cin>>n;string s;for(int i=1;i<=n;i++){cin>>s;pos[i]=insert(s);}build();cin>>s;for(int i=0,j=0;i<s.size();i++){j=tree[j].chd[s[i]-'a'];tree[j].cnt++;}dfs(0);for(int i=1;i<=n;i++) cout<<tree[pos[i]].cnt<<'\n';return 0;
}
ac自动机fail树上dfs序建可持久化线段树
待更新
upd:2020/2/2
子串能够表示为前缀的后缀,在Trie树中经过的节点是前缀,fail树上是后缀
#include<queue>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
constexpr int N=200010;
struct node1
{int chd[26],fail,fa;int id;
}tree[N];int idx1;
int h[N],e[N],ne[N],idx2;
int n,m,pos[N];
void add(int a,int b){e[idx2]=b,ne[idx2]=h[a],h[a]=idx2++;}
void insert(string &s,int id)
{int p=0;for(int i=0;i<s.size();i++){int &chd=tree[p].chd[s[i]-'a'];if(!chd) {chd=++idx1;tree[chd].fa=p;}p=chd;}tree[p].id=id;pos[id]=p;
}
void build()
{queue<int> q;for(int i=0;i<26;i++){int chd=tree[0].chd[i];if(!chd) continue;q.push(chd);}while(q.size()){int t=q.front();q.pop();add(tree[t].fail,t); //建fail树for(int i=0;i<26;i++){int &chd=tree[t].chd[i];if(chd)tree[chd].fail=tree[tree[t].fail].chd[i],q.push(chd);elsechd=tree[tree[t].fail].chd[i];}}
}
struct node2
{int l,r;int val;
}T[40*N];
int root[N],cnt;
void update(int l,int r,int pre,int &now,int pos,int val)
{now=++cnt;T[now]=T[pre];T[now].val+=val;if(l==r) return;int mid=l+r>>1;if(pos<=mid) update(l,mid,T[pre].l,T[now].l,pos,val);elseupdate(mid+1,r,T[pre].r,T[now].r,pos,val);
}
int query(int u,int l,int r,int L,int R)
{if(!u) return 0;if(L<=l&&r<=R) return T[u].val;int mid=l+r>>1;int v=0;if(L<=mid) v+=query(T[u].l,l,mid,L,R);if(R>mid) v+=query(T[u].r,mid+1,r,L,R);return v;
}
int dfn[N],sz[N],timestamp;
void dfs(int u)
{dfn[u]=++timestamp;sz[u]=1;for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];dfs(j);sz[u]+=sz[j];}
}
int main()
{ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);cin>>n>>m;memset(h,-1,sizeof h);for(int i=1;i<=n;i++){string s;cin>>s;insert(s,i);}build();dfs(0);// dfs序for(int i=1;i<=n;i++) {update(1,timestamp,root[i-1],root[i],dfn[pos[i]],1);int p=tree[pos[i]].fa;while(p){update(1,timestamp,root[i],root[i],dfn[p],1);p=tree[p].fa;}}while(m--){int l,r,k;cin>>l>>r>>k;cout<<query(root[r],1,timestamp,dfn[pos[k]],dfn[pos[k]]+sz[pos[k]]-1)-query(root[l-1],1,timestamp,dfn[pos[k]],dfn[pos[k]]+sz[pos[k]]-1)<<'\n';}return 0;
}