题意
有n个字符串,给出方式:
第i行输入操作序号,如果是1,后面接一个字符,说明这个字符串只有一个字符
如果是2,后面接一个编号j
,和一个字符,说明第i个字符串是在第j个字符串后面拼上一个字符,形成的。
然后有m次询问,每次给出一个字符串s和一个整数i,求在第i个字符串里字符串s出现了几次
数据范围
所有整数小于等于4e5,询问字符串总长小于等于4e5
解法
这个题目首先是将询问串建AC自动机,然后在原串形成的树(可以观察原来的字符串形成了一些树状结构)上跑,查询答案的时候相当于询问某个字符串在AC自动机上出现了几次,这里正确的原因是因为我们在原串形成的树上dfs的时候,其实就维护了当前这条链的AC自动机的信息。这里需要将AC自动机进行子树加操作,使用欧拉序就可以维护了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5+5;
inline int read(){
char c=getchar();int t=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,m;
typedef pair<int,int> pii;
vector<pii> son[maxn],q[maxn];
char c[maxn],s[5];
int ch[maxn][26],val[maxn],fail[maxn],cnt;
inline int add(){
int now=0,l=strlen(c);
for(int i=0;i<l;i++){
if(!ch[now][c[i]-'a'])ch[now][c[i]-'a']=++cnt;
now=ch[now][c[i]-'a'];
}
return now;
}
vector<int> F[maxn];
void build(){
queue<int> q;
for(int i=0;i<26;i++)if(ch[0][i])q.push(ch[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;i++){
if(ch[u][i]){
fail[ch[u][i]]=ch[fail[u]][i];
q.push(ch[u][i]);
}
else{ch[u][i]=ch[fail[u]][i];}
}
}
for(int i=1;i<=cnt;i++)F[fail[i]].push_back(i);
}
int dfn,din[maxn],dout[maxn],ans[maxn];
void dfs(int u){
din[u]=++dfn;
for(int i=0;i<F[u].size();i++){
int v=F[u][i];
dfs(v);
}
dout[u]=dfn;
}
int tr[maxn*5];
inline int lowbit(int x){return x&(-x);}
inline void modify(int x,int val){
while(x<=dfn){tr[x]+=val;x+=lowbit(x);}
}
inline int query(int x){
int ans=0;
while(x){ans+=tr[x];x-=lowbit(x);}
return ans;
}
void dfs2(int u,int now){
modify(din[u],1);
for(int i=0;i<q[now].size();i++){
pii t=q[now][i];
ans[t.second]=query(dout[t.first])-query(din[t.first]-1);
}
for(int i=0;i<son[now].size();i++){
pii t=son[now][i];
dfs2(ch[u][t.first],t.second);
}
modify(din[u],-1);
}
int main(){
n=read();
for(int i=1;i<=n;i++){
int op=read();int fa=0;
if(op==1);
else{fa=read();}
scanf("%s",s);
son[fa].push_back(pii(s[0]-'a',i));
}
m=read();
for(int i=1;i<=m;i++){
int d;
scanf("%d%s",&d,c);
q[d].push_back(pii(add(),i));
}
build();
dfs(0);
dfs2(0,0);
for(int i=1;i<=m;i++){
printf("%d\n",ans[i]);
}
return 0;
}