【题解】CF163E e-Government
题意
题目要求在一个可修改的字符串集中进行多模匹配,添加和删除的字符串在一开始给出。
思路过程
看到多模匹配,首先想到AC自动机,但是这道题目会删除原有字符串,所以考虑在AC自动机模板的多模匹配上进行修改。
AC自动机(普通):建一棵Trie,在每个字符串结尾节点标记 \(end\) 为 \(1\) ,建 fail 树和 Trie 图,建 fail 树时沿树枝边下传 \(end\) 节点数,在 Trie 图上跑节点,累加跑到节点的 \(end\) 为答案。
那此题要怎么做呢?
不难发现,一个节点的 \(end\) 为在它自身结尾的字符串数加上它在 fail 树上的祖先节点结尾的字符串树。
所以,删去一个字符串就是找到它尾部字符所对应的节点,然后将 fail 树中此节点的子树上的每个点(也就是每个以此节点为祖先的节点)的 \(end\) 值 \(-1\) 。
换句话说,删除和添加操作就是在一颗树上每次找一个节点,将它子树中所有点的权值加 \(1\) 或减 \(1\) 。
同理,询问操作就是在树上询问一个节点的权。
在预处理出这棵树的dfs序后,操作就可以了区间修改、单点查询的裸线段树/树状数组维护。
因为写得更少常数小,我选的树状数组
code
#include<cstdio>
#include<queue>
using std::queue;
#define re register
#define fr(k) for(re int k=0;k<26;k++)
const int N=1e6+9;
int t,cnt,tot,tr[N][26],fail[N],id[N],xl[N],xr[N],h[N],v[N],ne[N];
char s[N];
bool del[N];
struct BIT{
int f[N],n;
inline void add(int p,int q,int k){
for(;p<=n;p+=(p&-p)) f[p]+=k;
for(;q<=n;q+=(q&-q)) f[q]-=k;
}
inline int ask(int x){int res=0;for(;x;x^=(x&-x)) res+=f[x];return res;}
}bit;
inline void addedge(int x,int y){v[++t]=y,ne[t]=h[x],h[x]=t;}
inline void adds(int k){
int x=0,i=0,p;
scanf("%s",s+1);
while(s[++i]) p=s[i]-'a',x=tr[x][p]?tr[x][p]:(tr[x][p]=++tot);
id[k]=x;
}
inline void buildfail(){
int x;queue<int> q;
fr(k) if(tr[0][k]) addedge(0,tr[0][k]),q.push(tr[0][k]);
while(!q.empty()){
x=q.front(),q.pop();
fr(k)
if(tr[x][k]) fail[tr[x][k]]=tr[fail[x]][k],addedge(fail[tr[x][k]],tr[x][k]),q.push(tr[x][k]);
else tr[x][k]=tr[fail[x]][k];
}
}
void dfs(int x){
xl[x]=++cnt;
for(re int i=h[x];i;i=ne[i]) dfs(v[i]);
xr[x]=cnt+1;
}
inline int query(){
int x=0,i=0,ans=0;
while(s[++i])
x=tr[x][s[i]-'a'],ans+=bit.ask(xl[x]);
return ans;
}
int main(){
int q,n;scanf("%d%d",&q,&n);
for(re int i=1;i<=n;i++) adds(i);
buildfail(),dfs(0);bit.n=cnt;
for(re int i=1;i<=n;i++) bit.add(xl[id[i]],xr[id[i]],1);
for(re int i=1,x,j;i<=q;i++){
scanf("%s",s);
if(s[0]=='?'){printf("%d\n",query());continue;}
j=0,x=0;
while(s[++j]) x=(x<<3)+(x<<1)+(s[j]^48);
if(s[0]=='-'){if(!del[x]) del[x]=1,bit.add(xl[id[x]],xr[id[x]],-1);}
else {if(del[x]) del[x]=0,bit.add(xl[id[x]],xr[id[x]],1);}
}
return 0;
}
求点个赞,谢谢!