CF710F String Set Queries

题目

CF710F String Set Queries

做法

很好的题目(AC自动机)

支持三种操作:插入,删除,查询

删除很好做,再建个自动机然后差分就行了

题目难点主要是插入,对于每个新来的串都重构,T是肯定的

这题我们用二进制来解决,对于插入和删除建多个自动机,然后查询时累加所属的多个自动机贡献

重点讲下怎么重构吧,反正juruo是第一次了解到,打\(*\)号的是与平时不同的地方:

	inline void F_trie(LL rt){
		sum[rt]=0,fail[rt]=rt;
		queue<LL>que; que.push(rt);
		for(LL i=0;i<26;++i) son[rt][i]=rt;
		while(que.size()){
			LL u(que.front());que.pop();
			sum[u]=sum[fail[u]]+val[u];
			for(LL i=0;i<26;++i){
				LL v(tmp[u][i]);
				if(v){
					que.push(v),
					fail[v]=son[fail[u]][i],
					son[u][i]=v;
				}else son[u][i]=son[fail[u]][i];
			}
		}
	}

对于儿子结点,我们开两个数组\(tmp暂时储存,son真(*)\),这里的结点都不为0(*),每次对于一个自动机添加串,加到\(tmp\)
而构造\(trie\)图时,我们再对\(son\)进行操作,首先把自动机根结点加入\(rt\)要遍历的队列,\(fail[rt]=rt,son[rt][i]=rt\),就如同平时
\(0\)根节点及空儿子\(fail\)指向根节点,\(fail[v]=son[fail[u]][i], son[u][i]=v;\)两句不能颠倒,防止\(fail\)指正指向自己的情况

My complete code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef int LL;
const LL maxn=300009;
inline LL Read(){
	LL x(0),f(1);char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*f;
}
char s[maxn];
struct ACauto{
	LL nod;
	LL val[maxn],tmp[maxn][26],son[maxn][26],sum[maxn],fail[maxn],root[25],t[25];
	inline void B_trie(LL &rt){
		if(!rt) rt=++nod;
		LL now=rt;
		for(LL i=1,Len=strlen(s+1);i<=Len;++i){
			LL c(s[i]-'a');
			if(!tmp[now][c]) tmp[now][c]=++nod;
			now=tmp[now][c];
		}++val[now];
	}
	inline LL Merge(LL x,LL y){
		if(!x||!y) return x+y;
		val[x]+=val[y];
		for(LL i=0;i<26;++i)
		    tmp[x][i]=Merge(tmp[x][i],tmp[y][i]);
		return x;
	}
	inline void F_trie(LL rt){
		sum[rt]=0,fail[rt]=rt;
		queue<LL>que; que.push(rt);
		for(LL i=0;i<26;++i) son[rt][i]=rt;
		while(que.size()){
			LL u(que.front());que.pop();
			sum[u]=sum[fail[u]]+val[u];
			for(LL i=0;i<26;++i){
				LL v(tmp[u][i]);
				if(v){
					que.push(v),
					fail[v]=son[fail[u]][i];
					son[u][i]=v;
				}else son[u][i]=son[fail[u]][i];
			}
		}
	}
	inline void Insert(){
		B_trie(root[0]);
		LL i(0);
		for(;t[i]==1;++i){
		    root[i+1]=Merge(root[i+1],root[i]);
		    root[i]=0,
		    t[i]^=1;
		}
		t[i]^=1,F_trie(root[i]);
	}
	inline LL Query(){
		LL ret(0),Len=strlen(s+1);
		for(LL i=0;i<=21;++i){
			if(root[i]==0) continue;
			LL now(root[i]);
			for(LL j=1;j<=Len;++j){
				LL c(s[j]-'a');
				now=son[now][c];
				ret+=sum[now];
			}
		}
		return ret;
	}
}In,Del;
int main(){
	LL T=Read();
	while(T--){
		LL op(Read());
		scanf(" %s",s+1);
		if(op==1) In.Insert();
		else if(op==2) Del.Insert();
		else printf("%d\n",In.Query()-Del.Query()),fflush(stdout);
	}return 0;
}/*
*/
posted @ 2019-01-21 17:06  y2823774827y  阅读(179)  评论(0编辑  收藏  举报