假如没有删除添加操作,那么就是一个 A C AC AC自动机的板题
把所有字符串集合建立 A C A M ACAM ACAM
然后对于每个询问串,设询问串在 t i r e tire tire树上的 u u u节点
那我们可以对询问串的每个前缀去暴力跳 f a i l fail fail算答案贡献
但是这样太慢,我们可以建出 f a i l fail fail树统计子树和快速得到答案
但是现在有删除,添加字符串的操作
想一下,节点 u u u造成的贡献,也就是 f a i l fail fail树种所有 u u u的子节点的答案都加一
所有我们可以求出 f a i l fail fail树的 d f s dfs dfs序快速修改答案
区间修改使用树状数组差分
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int zi[maxn][27],ed[maxn],id,ok[maxn],fail[maxn],num[maxn];
char a[maxn];
void insert(char a[maxn],int kl )
{
int now = 0, len = strlen( a+1 );
for(int i=1;i<=len;i++)
{
if( zi[now][a[i]-'a']==0 ) zi[now][a[i]-'a'] = ++id;
now = zi[now][a[i]-'a'];
}
ed[now]++; num[kl] = now;
}
void get_fail()
{
queue<int>q;
for(int i=0;i<=25;i++)
if( zi[0][i] ) q.push( zi[0][i] );
while( !q.empty() )
{
int u = q.front(); q.pop();
ed[u] += ed[fail[u]];
for(int i=0;i<=25;i++)
{
if( zi[u][i] )
fail[zi[u][i]] = zi[fail[u]][i],q.push( zi[u][i] );
else zi[u][i] = zi[fail[u]][i];
}
}
}
vector<int>vec[maxn];
void get_failtree()
{
for(int i=1;i<=id;i++) vec[fail[i]].push_back(i);
}
int dfn[maxn],dfu,low[maxn];
void dfs_failtree(int u)
{
dfn[u] = ++dfu;
for( auto v:vec[u] ) dfs_failtree(v);
low[u] = dfu;
}
struct tree_array
{
int sum[maxn],n;
int lowbit(int x){ return x&(-x); }
void add(int x,int val){for(;x<=n;x+=lowbit(x)) sum[x]+=val; }
int ask(int x){int ans=0;for(;x;x-=lowbit(x)) ans+=sum[x]; return ans; }
}t;
int main()
{
int n,k; cin >> n >> k;
for(int i=1;i<=k;i++)
{
scanf("%s",a+1 );
insert( a,i ); ok[i] = 1;
}
get_fail(); get_failtree(); dfs_failtree(0);
t.n = id+1;
for(int i=1;i<=n;i++)
{
scanf("%s",a+1); int len = strlen( a+1 );
if( a[1]=='+'||a[1]=='-' )
{
int sum = 0;
for(int j=2;j<=len;j++) sum = sum*10+( a[j]-'0' );
if( a[1]=='+' )
{
if( ok[sum] ) continue;
ok[sum] = 1; sum = num[sum];
t.add( dfn[sum],1 ); t.add( low[sum]+1,-1 );
}
else
{
if( !ok[sum] ) continue;
ok[sum] = 0; sum = num[sum];
t.add( dfn[sum],-1 ); t.add( low[sum]+1,1 );
}
}
else
{
int now = 0, ans = 0;
for(int j=2;j<=len;j++)
{
now = zi[now][a[j]-'a'];
ans += ed[now]+t.ask( dfn[now] );
}
cout << ans << endl;
}
}
}