题目描述:
Alice有
n
n
n个字符串
S
1
,
S
2
,
.
.
.
,
S
n
S_1,S_2,...,S_n
S1,S2,...,Sn,Bob有一个字符串集合
T
T
T,一开始集合是空的。
接下来会发生 q q q次操作,操作有两种形式:
1. 1.P Bob往自己的集合里添加了一个字符串P
2. 2 x Alice询问Bob,集合T中有多少个字符串包含串sx,(我们称串A包含串B,当且仅当B是A的子串)
题解:
用n个字符串
S
1
,
S
2
,
.
.
.
S
n
S_1,S_2,...S_n
S1,S2,...Sn建立AC自动机,扒出fail树,然后每添加一个P串,就把它拿到AC自动机上跑一遍,把到达的结点都记录下来,由于对每个串都只贡献一次,所以这一次的贡献就是这些点到根节点的树链的并。
然后求树链的并,我们只需要将所有结点按照DFS序排序,把每个点的权值+1,相邻结点的LCA的权值-1即可。
最后用树状数组单点修改+计算子树和完成收尾工作
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define LL long long
#define pii pair<int,int>
#define mp(a,b) make_pair(a,b)
const int MAXN = 2e6+10;
const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
int dep[MAXN],f[MAXN][24],dfn[MAXN],sz[MAXN],head[MAXN];
int nxt[MAXN][26],fail[MAXN],id[MAXN],a[MAXN],bit[MAXN];
int tot,cnt,atot,n; char s[MAXN];
struct node{ int v,nxt; }edge[MAXN<<1];
inline void add_edge(int u,int v){
edge[++atot].v=v; edge[atot].nxt=head[u]; head[u]=atot;
}
inline void Insert(char *s,int k){
int len=strlen(s),rt=0;
for(int i=0;i<len;i++){
if(!nxt[rt][s[i]-'a']) nxt[rt][s[i]-'a']=++tot;
rt = nxt[rt][s[i]-'a'];
}
id[k]=rt;
}
inline void Build(){
queue<int> que;
for(int i=0;i<26;i++) if(nxt[0][i]) que.push(nxt[0][i]),add_edge(0,nxt[0][i]);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=0;i<26;i++){
if(nxt[u][i]){
fail[nxt[u][i]]=nxt[fail[u]][i];
que.push(nxt[u][i]);
add_edge(fail[nxt[u][i]],nxt[u][i]);
}else{
nxt[u][i]=nxt[fail[u]][i];
}
}
}
}
void dfs(int u,int fa){
f[u][0]=fa; dep[u]=dep[fa]+1; dfn[u]=++cnt; sz[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v = edge[i].v;
if(v == fa) continue;
dfs(v,u);
sz[u] += sz[v];
}
}
inline void Init(){
for(int j=1;j<=21;j++)
for(int i=1;i<=cnt;i++)
f[i][j]=f[f[i][j-1]][j-1];
}
inline int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=21;i>=0;i--)
if(dep[f[x][i]]>=dep[y])
x=f[x][i];
if(x==y) return x;
for(int i=21;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
inline int lowbit(int x){ return x&-x; }
inline void add(int x,int v){ for(int i=x;i<=cnt;i+=lowbit(i)) bit[i]+=v; }
inline int query(int x,int res=0){ for(int i=x;i;i-=lowbit(i)) res+=bit[i]; return res; }
inline bool cmp(int x,int y){ return dfn[x]<dfn[y]; }
inline void update(char *s){
int rt=0,len=strlen(s),m=0;
a[m++]=0;
for(int i=0;i<len;i++) rt=nxt[rt][s[i]-'a'],a[m++]=rt;
sort(a,a+m,cmp);
int k = unique(a,a+m)-a;
for(int i=0;i<k;i++){
add(dfn[a[i]],1);
if(i) add(dfn[LCA(a[i-1],a[i])],-1);
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
#endif // ONLINE_JUDGE
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%s",s),Insert(s,i);
Build(); dfs(0,0); Init();
int Q; scanf("%d",&Q);
while(Q--){
int op; scanf("%d",&op);
if(op==1) scanf("%s",s),update(s);
else{
int x; scanf("%d",&x);
int l=dfn[id[x]],r=dfn[id[x]]+sz[id[x]]-1;
printf("%d\n",query(r)-query(l-1));
}
}
return 0;
}