AC 自動機+fail樹DFS序+樹狀數組
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 1000010
int n,m,DFS_tot,Size,S_tot;
struct Node{
int to,next;
}edge[N*2];
int l[N],r[N],sum[N],head[N],id[N];
bool flag[N];
inline int lowbit(int x)
{
return x&(-x);
}
void Add(int x,int val)
{
for(int i=x;i<=Size;i+=lowbit(i))
sum[i]+=val;
}
int Sum(int x)
{
int Nowsum=0;
for(int i=x;i>0;i-=lowbit(i))
Nowsum+=sum[i];
return Nowsum;
}
void Addedge(int u,int v)
{
S_tot++;edge[S_tot].next=head[u];edge[S_tot].to=v;head[u]=S_tot;
}
void DFS(int k)
{
l[k]=++DFS_tot;
for(int i=head[k];i;i=edge[i].next)
{
int v=edge[i].to;
DFS(v);
}
r[k]=DFS_tot;
}
struct AcAuto{
int next[N][26],fail[N],end[N];
int tot,root;
int New_node()
{
for(int i=0;i<26;i++)
next[tot][i]=-1;
end[tot++]=0;
return tot-1;
}
void Init()
{
tot=0;
root=New_node();
}
void Insert(char *T,int _id)
{
int len=(int)strlen(T);
int now=root;
for(int i=0;i<len;i++)
{
int num=T[i]-'a';
if(next[now][num]==-1)
next[now][num]=New_node();
now=next[now][num];
}
end[now]=1;
id[_id]=now;
}
void Build_Failtree()
{
queue<int>Q;
fail[root]=root;
for(int i=0;i<26;i++)
{
if(next[root][i]==-1)
next[root][i]=root;
else
{
fail[next[root][i]]=root;
Q.push(next[root][i]);
}
}
while(!Q.empty())
{
int now=Q.front();Q.pop();
end[now]+=end[fail[now]];
for(int i=0;i<26;i++)
{
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else
{
fail[next[now][i]]=next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
}
void Query(char *T)
{
int Ans=0;
int len=(int)strlen(T);
int now=root;
for(int i=0;i<len;i++)
{
int num=T[i]-'a';
now=next[now][num];
if(end[now])
Ans+=Sum(l[now]);
}
printf("%d\n",Ans);
return;
}
};
AcAuto A;
char S[N];
int main()
{
scanf("%d%d",&m,&n);
A.Init();
for(int i=1;i<=n;i++)
{
scanf("%s",S);
A.Insert(S,i);
}
A.Build_Failtree();
Size=A.tot;
for(int i=0;i<A.tot;i++)
{
if(A.fail[i]!=i)
Addedge(A.fail[i],i);
}
DFS(A.root);
for(int i=0;i<Size;i++)
{
Add(l[i],A.end[i]);Add(l[i]+1,-A.end[i]);
}
char Ch;
for(int i=1;i<=m;i++)
{
scanf(" %c",&Ch);
if(Ch=='?')
{
scanf("%s",S);
A.Query(S);
}
else if(Ch=='+')
{
int num;scanf("%d",&num);
if(flag[num])
{
flag[num]^=1;
Add(l[id[num]],1);Add(r[id[num]]+1,-1);
}
}
else
{
int num;scanf("%d",&num);
if(!flag[num])
{
flag[num]^=1;
Add(l[id[num]],-1);Add(r[id[num]]+1,1);
}
}
}
return 0;
}