• 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
    ",In.Query()-Del.Query()),fflush(stdout);
    	}return 0;
    }/*
    */
    
  • 相关阅读:
    在sublime中安装使用TortoiseSVN-sublime使用心得(4)
    怎么在sublime/emmet中加自定义的内容-sublime使用心得(3)
    Function学习
    null类型
    undefined类型
    《SQL语句的基本语法》《转》
    《SQL SERVER的数据类型》《转》
    SQL语句《转》
    Delphi防止多实例运行的两种方法《转》
    1.简单计算器
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10299792.html
Copyright © 2020-2023  润新知