算法标签:AC自动机
思路:
我们可以先把所有s串在AC 自动机上跑一遍,考虑如果一个串出现了,则我所能指向的所有fail节点都可以获得贡献,于是我们建出一棵fail树。
接下来考虑把T串加入,自己思考我们发现如果只是单纯把我到根节点的路径权值都+1,我们可能会重复计算答案,于是就要树链合并,即按照dfs序排序后,每一只修改我和上一个点的lca到我的路径,就不会重复。有点卡空间,我的做法是lca用线段树维护区间d最小值找出lca,时间(常数大)换空间了。
没有强制在线所以可以用AC自动机写,如果强制在线bzoj2555,就只能用数据结构套数据结构维护了,可怕。
以下代码:

#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=3e6+5,M=1e5+5; char s[N];queue<int> q; int minn[N<<2],ch[N][26],n,Q,tot=1,head[N],ne[N],to[N],num[N<<1],id[N],kk; int que[N],nt,g[N],d[N],cnt,dfn[N],sz[N],a[N],fail[N],idx; il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;} il void insert(int x,int y){ne[++cnt]=head[x];head[x]=cnt;to[cnt]=y;} bool cmp(int t1,int t2){return dfn[t1]<dfn[t2];} il void add(int x,int v){for(;x<=tot;x+=x&-x)g[x]+=v;} il int query(int x){int ans=0;for(;x;x-=x&-x)ans+=g[x];return ans;} il int Min(int x,int y){return d[x]<d[y]?x:y;} il int ins(){ int l=strlen(s+1);int x=1; for(int i=1;i<=l;i++){ if(!ch[x][s[i]-'a'])ch[x][s[i]-'a']=++tot; x=ch[x][s[i]-'a']; } return x; } il void dfs(int x){ dfn[x]=++idx;sz[x]=1;num[id[x]=++kk]=x; for(int i=head[x];i;i=ne[i]){ d[to[i]]=d[x]+1;dfs(to[i]); sz[x]+=sz[to[i]];num[++kk]=x; } } il void build(int x,int l,int r){ if(l==r){minn[x]=num[l];return;} int mid=(l+r)>>1; build(x<<1,l,mid);build(x<<1|1,mid+1,r); minn[x]=Min(minn[x<<1],minn[x<<1|1]); } il int qm(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr)return minn[x]; int mid=(l+r)>>1; if(qr<=mid)return qm(x<<1,l,mid,ql,qr); else if(mid<ql)return qm(x<<1|1,mid+1,r,ql,qr); else return Min(qm(x<<1,l,mid,ql,qr),qm(x<<1|1,mid+1,r,ql,qr)); } il int Lca(int x,int y){ int l=id[x],r=id[y];if(l>r)swap(l,r); return qm(1,1,kk,l,r); } int main() { n=read(); for(int i=1;i<=n;i++){scanf(" %s",s+1);a[i]=ins();} q.push(1); while(!q.empty()){ int x=q.front();q.pop(); for(int i=0;i<26;i++){ if(!ch[x][i])continue; int tmp=fail[x]; while(tmp>1&&!ch[tmp][i])tmp=fail[tmp]; if(ch[tmp][i])fail[ch[x][i]]=ch[tmp][i]; else fail[ch[x][i]]=1;q.push(ch[x][i]); } } for(int i=2;i<=tot;i++)insert(fail[i],i); d[1]=1;dfs(1);build(1,1,kk);int Q=read(); while(Q--){ int op=read(); if(op==1){ scanf(" %s",s+1);int l=strlen(s+1); int x=1,nt=0;que[++nt]=x; for(int i=1;i<=l;i++){ while(x!=1&&!ch[x][s[i]-'a'])x=fail[x]; if(ch[s[i]-'a'])x=ch[x][s[i]-'a'];que[++nt]=x; } sort(que+1,que+1+nt,cmp);add(dfn[que[1]],1); for(int j=2;j<=nt;j++){ add(dfn[que[j]],1); add(dfn[Lca(que[j],que[j-1])],-1); } } else{ int x=a[read()];printf("%d ",query(dfn[x]+sz[x]-1)-query(dfn[x]-1)); } } return 0; }