题意
给你一棵树,
个节点,每个节点有一个字母,给出Q个询问,询问有多少个节点从下到上能够跟询问串匹配
分析
把询问串和树并在一起,然后建立fail树,siz从深度大到深度小合并,询问就询问fail树的某个点的子树siz和就好了
代码
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define PB push_back
#define CL clear
//#define int long long
#define fi first
#define se second
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef pair<int,int> pii;
const int N = 2e6+10;
const int inf = 1e9;
const int mod = 1e9+7;
inline int rd() {
char ch = getchar(); int p = 0; int f = 1;
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
struct Tire{
int son[N][27],fail[N],siz[N],R[N],step[N],px[N];
queue<int> q;
int rt,tot;
void init(){memset(son,0,sizeof(son)); memset(step,0,sizeof(step)); memset(fail,0,sizeof(fail)); rt = tot = 0;}
int ins(int f,char ch,int sz) {
int nx = ch - 'A' + 1;
if(!son[f][nx]){son[f][nx] = ++tot;}
int u = son[f][nx];
step[u] = step[f] + 1; siz[u] += sz;
return u;
}
void AC_Tire() {
while(!q.empty()) q.pop(); q.push(0);
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i=1;i<=26;++i) {
if(!son[u][i]) {
if(u==rt) son[u][i] = 0;
else son[u][i] = son[fail[u]][i];
}
else {
if(u==rt) fail[son[u][i]] = 0;
else fail[son[u][i]] = son[fail[u]][i];
q.push(son[u][i]);
}
}
}
}
void calc() {
for(int i=1;i<=tot;++i) R[step[i]] ++;
for(int i=1;i<=tot;++i) R[i] += R[i-1];
for(int i=tot;i>=1;--i) px[R[step[i]]--] = i;
for(int i=tot;i>=1;--i) {
siz[fail[px[i]]] += siz[px[i]];
}
}
}tire;
char s[N]; int pos[N];
signed main() {
int n = rd(); int k = rd(); tire.init();
rep(i,1,n) {
char ch; scanf("\n%c",&ch);
int f = rd();
tire.ins(f,ch,1);
}
rep(i,1,k) {
scanf("%s",s+1); int len = strlen(s+1); reverse(s+1,s+len+1);
int f = 0; rep(j,1,len) {
f=tire.ins(f,s[j],0);
}pos[i] = f;
}
tire.AC_Tire();
tire.calc();
// for(int i=1;i<=tire.tot;i++) printf("%lld ",tire.siz[i]);
rep(i,1,k){
printf("%d\n",tire.siz[pos[i]]);
}
return 0;
}