Codeforces 1204G-Indie Album
题意
有n个字符串,对于第i个字符串通过以下两种方式中的一个给出。
1、 1 c,该字符串只含一个字符c。
2、 2 j c,该字符串为第j个字符串末尾添加一个字符c得到。
m次询问,每次询问给出一个整数x和一个字符串s,问在第x个字符串中,字符串s出现了几次。
题解
对于m个询问的字符串,构建AC自动机,利用fail树的性质:将母串在AC自动机上跑一遍并将走到的位置权值+1后,一个字符串在母串中出现的次数就是该字符串所对应的fail节点的子树权值和。
发现给出的n个字符串也是一棵树的形式,所以可以在树上dfs,利用dfs序和树状数组查询fail节点的字数权值和。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int n,m;
int fa[N],ans[N];
char s[N],t[N];
int ver[N],head[N],nxt[N],tt;
int tr[N][26],fail[N],tot;
int dfn[N],id,Size[N];
int c[N];
vector<pair<int,int> > que[N];
void add(int u,int v){
ver[++tt]=v;
nxt[tt]=head[u];head[u]=tt;
}
int insert(char *s,int len){
int u=0;
for(int i=1;i<=len;i++){
int ch=s[i]-'a';
if(!tr[u][ch]) tr[u][ch]=++tot;
u=tr[u][ch];
}
return u;
}
queue<int> q;
vector<int> E[N];
void build(){
for(int i=0;i<26;i++){
if(tr[0][i]) q.push(tr[0][i]);
}
while(q.size()){
int u=q.front();q.pop();
E[fail[u]].push_back(u);
for(int i=0;i<26;i++){
if(tr[u][i]){
fail[tr[u][i]]=tr[fail[u]][i];
q.push(tr[u][i]);
}else tr[u][i]=tr[fail[u]][i];
}
}
}
void AC_dfs(int u){
int k=E[u].size();
dfn[u]=++id;
Size[u]=1;
for(int i=0;i<k;i++){
int v=E[u][i];
AC_dfs(v);
Size[u]+=Size[v];
}
}
void update(int x,int y){
for(;x<=id;x+=(x&-x)) c[x]+=y;
}
int query(int x){
int ans=0;
for(;x;x-=(x&-x)) ans+=c[x];
return ans;
}
int solve(int x){
return query(dfn[x]+Size[x]-1)-query(dfn[x]-1);
}
void dfs(int x,int u){
int ch=s[x]-'a';
u=tr[u][ch];
update(dfn[u],1);
for(int i=head[x];i;i=nxt[i]){
int v=ver[i];
dfs(v,u);
}
int k=que[x].size();
for(int i=0;i<k;i++){
ans[que[x][i].second]=solve(que[x][i].first);
}
update(dfn[u],-1);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
int op,x;
scanf("%d",&op);
if(op==2){
scanf("%d",&x);
fa[i]=x;
}
add(fa[i],i);
scanf("%s",&s[i]);
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
int idx;
scanf("%d",&idx);
scanf("%s",t+1);
int len=strlen(t+1);
int e=insert(t,len);
que[idx].push_back(make_pair(e,i));
}
build();
AC_dfs(0);
for(int i=1;i<=n;i++){
if(!fa[i]) dfs(i,0);
}
for(int i=1;i<=m;i++){
printf("%d\n",ans[i]);
}
return 0;
}