【题解】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;
}

求点个赞,谢谢!

posted @ 2021-07-03 19:19  WhaleAtCola  阅读(139)  评论(0编辑  收藏  举报