很容易想到用AC自动机(预处理surnames)或者后缀数据结构(处理Text)来解,但前一种方法不好处理插入和删除操作,而后一种方法由于surnames和询问次数过多会TLE,正确解法是处理AC自动机fail逆向树的dfs序列(要好好理解一下fial逆向树),与阿狸的打字机不同,《阿狸的打字机》一题中是对序列单点修改,区间求和, 而这题需要单点求值,区间修改,但这俩种功能都可以通过树状数组高效实现。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>
#include <map>
#include <string>
#include <climits>
#include <set>
#include <string>
#include <sstream>
#include <utility>
#include <ctime>
using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;
const int MAXN(1000010);
const int MAXM(200010);
const int MAXE(200010);
const int HSIZE(3131);
const int SIGMA_SIZE(26);
const int MAXH(19);
const int INFI((INT_MAX-1) >> 1);
const int MOD(7777777);
const ULL BASE(31);
const LL LIM(10000000);
const int INV(-10000);
struct FENWICK_TREE
{
int table[MAXN];
int size;
void init(int tn)
{
size = tn;
memset(table+1, 0, sizeof(table[0])*size);
}
void add(int sour, int value)
{
for(int i = sour; i <= size; i += i&-i)
table[i] += value;
}
int query(int sour)
{
int ret = 0;
for(int i = sour; i >= 1; i -= i&-i)
ret += table[i];
return ret;
}
};
FENWICK_TREE ft;
int left[MAXN], right[MAXN];
int count;
struct TREE
{
struct EDGE
{
int v, next;
};
int first[MAXN];
EDGE edge[MAXN];
int rear;
void init(int tn)
{
memset(first, -1, sizeof(first[0])*(tn+1));
rear = 0;
}
void insert(int tu, int tv)
{
edge[rear].v = tv;
edge[rear].next = first[tu];
first[tu] = rear++;
}
void dfs(int u)
{
left[u] = ++count;
for(int i = first[u]; ~i; i = edge[i].next)
dfs(edge[i].v);
right[u] = count;
}
};
TREE tree;
bool del[100010];
int ind[100010];
char str[MAXN];
struct AC
{
int ch[MAXN][SIGMA_SIZE];
int val[MAXN], f[MAXN];
int size;
inline int idx(char temp) {return temp-'a';}
void init()
{
memset(ch[0], 0, sizeof(ch[0]));
f[0] = val[0] = 0;
size = 1;
}
void insert(char *S, int tn)
{
int u = 0, id;
for(char *sp = S; *sp; ++sp)
{
id = idx(*sp);
if(!ch[u][id])
{
memset(ch[size], 0, sizeof(ch[size]));
f[0] = val[0] = 0;
ch[u][id] = size++;
}
u = ch[u][id];
}
val[u] = 1;
ind[tn] = u;
}
int que[MAXN], front, back;
void construct()
{
int u, cur;
front = back = 0;
for(int i = 0; i < SIGMA_SIZE; ++i)
if(ch[0][i])
{
que[back++] = ch[0][i];
f[ch[0][i]] = 0;
}
while(front < back)
{
cur = que[front++];
for(int i = 0; i < SIGMA_SIZE; ++i)
{
u = ch[cur][i];
if(u)
{
que[back++] = u;
f[u] = ch[f[cur]][i];
val[u] += val[f[u]];
}
else
ch[cur][i] = ch[f[cur]][i];
}
}
}
int query(char *S)
{
int u = 0, ret = 0, id;
for(char *sp = S; *sp; ++sp)
{
id = idx(*sp);
u = ch[u][id];
if(val[u])
ret += ft.query(left[u]);
}
return ret;
}
};
AC ac;
void solve(int n, int K)
{
ac.init();
for(int i = 1; i <= K; ++i)
{
scanf("%s", str);
ac.insert(str, i);
del[i] = false;
}
ac.construct();
tree.init(ac.size);
for(int i = 1; i < ac.size; ++i)
tree.insert(ac.f[i], i);
count = 0;
tree.dfs(0);
ft.init(ac.size);
for(int i = 0; i < ac.size; ++i)
{
ft.add(left[i], ac.val[i]);
ft.add(left[i]+1, -ac.val[i]);
}
char flag;
int temp;
for(int i = 0; i < n; ++i)
{
scanf(" %c", &flag);
if(flag == '?')
{
scanf("%s", str);
printf("%d\n", ac.query(str));
}
else if(flag == '+')
{
scanf("%d", &temp);
if(del[temp])
{
del[temp] = false;
ft.add(left[ind[temp]], 1);
ft.add(right[ind[temp]]+1, -1);
}
}
else
{
scanf("%d", &temp);
if(!del[temp])
{
del[temp] = true;
ft.add(left[ind[temp]], -1);
ft.add(right[ind[temp]]+1, 1);
}
}
}
}
int main()
{
int n, K;
while(~scanf("%d%d", &n, &K))
{
solve(n, K);
}
return 0;
}