LINK

假如没有删除添加操作,那么就是一个 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;
		}
	}
}