咕了好久没更博客,最近得知可以去冬眠营玩耍,还可以搭顺风车回广州过年

(最近做到的比较有意思的题目:bzoj3958、hihocoder1419)

Problem

Codeforces-710F--洛谷提交入口

题目概要:维护一个字符串集合,要求支持:加字符串、删字符串和查询当前所有已加入且未被删除的字符串在给出模板串中出现的次数(操作数&字符串总长\(\leq 3\times 10^5\))

Solution

挺有意思的一道题

看到多串匹配就猜测是AC自动机,然后动态加串删串不好处理

就将加入和删除维护两份,每份只需要维护加入即可,最后处理答案就在加入部分中匹配数减去删除部分中的匹配数(就像那个维护删除堆的套路)

(然后就可以分块了……一些短串就直接暴力重建AC自动机,而对于长串就处理出kmp数组直接kmp)

但是这个想法太惊悚了,不敢尝试

于是乎就有了二项堆的思想:维护二项堆核心思想就是二进制分组(第\(i\)个堆拥有\(2^i\)个元素,第\(i\)个堆可以由两个第\(i-1\)个堆合并而成)

类似的,这里可以将堆换为AC自动机:\(i\)号AC自动机维护\(2^i\)个串,若有两个\(i\)号AC自动机则合并成一个\(i+1\)号AC自动机,合并是拆除原AC自动机,然后暴力合并)

即使这样暴力,但每个串只会被合并\(log_2m\)次,而且每次查询只要在\(log_2m\)个AC自动机中查询即可,复杂度为AC自动机的复杂度再带个\(log_m\)

Code

注意内存回收,还有合并的时候可以直接trie树合并(但前提是不能将fail指针作为儿子以求速度)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll; inline void read(int&x){
char c11=getchar();x=0;while(!isdigit(c11))c11=getchar();
while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
} const int N=601000;
struct node{
int ch[26],fail,end,sum;
inline void clear(){
for(int i=0;i<26;++i)ch[i]=0;
fail=end=sum=0;
}
}p[N]; struct RECYCLE{
int stk[N],top,tot;
RECYCLE(){top=tot=0;}
inline int newnode(){return top?stk[top--]:++tot;}
inline void del(int x){stk[++top]=x;p[x].clear();}
}re; struct AC_Auto{
int rt;
void clear(){p[rt=re.newnode()].fail=0;}
inline void ins(char*a){
int nw=rt;
for(int i=0,x;a[i];++i){
x=a[i]-'a';
if(!p[nw].ch[x])p[nw].ch[x]=re.newnode();
nw=p[nw].ch[x];
}++p[nw].end;
}
void build(){
static int q[N],he,ta;
q[he=ta=1]=rt;
while(he<=ta){
int x=q[he++];
for(int i=0,c,t;i<26;++i){
c=p[x].ch[i],t=p[x].fail;
if(!c)continue;
q[++ta]=c;
while(t && !p[t].ch[i])t = p[t].fail;
if(t&&p[t].ch[i]!=c)p[c].fail = p[t].ch[i];
else p[c].fail=rt;
p[c].sum = p[c].end + p[p[c].fail].sum;
}
}
} ll scan(char*s){
int nw=rt;ll res=0;
for(int i=0,x;s[i];++i){
x=s[i]-'a';
while(nw!=rt&&!p[nw].ch[x])nw=p[nw].fail;
if(p[nw].ch[x])nw=p[nw].ch[x];
res+=p[nw].sum;
}return res;
} void merge(int&x,int y){
if(!y)return ;
if(!x)x=re.newnode();
for(int i=0;i<26;++i)
merge(p[x].ch[i],p[y].ch[i]);
p[x].end+=p[y].end;
re.del(y);
}
}; struct NODE{
int tot,num[20];
AC_Auto ac[20];
NODE(){tot=0;memset(num,0,sizeof num);}
void INS(char*a){
num[++tot]=1;
ac[tot].clear();
ac[tot].ins(a);
while(tot>1)
if(num[tot]==num[tot-1]){
ac[tot-1].merge(ac[tot-1].rt,ac[tot].rt);
num[tot-1]+=num[tot];
num[tot]=0,--tot;
}
else break;
ac[tot].build();
}
ll MAT(char*a){
ll res=0ll;
for(int i=1;i<=tot;++i)
res+=ac[i].scan(a);
return res;
}
}A,B; char s[N]; int main(){
int m,op;read(m);
while(m--){
read(op);scanf("%s",s);
if(op==1)A.INS(s);
else if(op==2)B.INS(s);
else printf("%lld\n",A.MAT(s)-B.MAT(s)),fflush(stdout);
}return 0;
}

题解-Codeforces710F String Set Queries的更多相关文章

  1. 【Codeforces710F】String Set Queries (强制在线)AC自动机 + 二进制分组

    F. String Set Queries time limit per test:3 seconds memory limit per test:768 megabytes input:standa ...

  2. 【CF710F】String Set Queries(二进制分组,AC自动机)

    [CF710F]String Set Queries(二进制分组,AC自动机) 题面 洛谷 CF 翻译: 你有一个字符集合\(D\),初始为空, 有三种操作: 往\(D\)中加入一个串:从\(D\)中 ...

  3. CF710F String Set Queries

    CF710F String Set Queries 支持字符串的插入和删除...SAM也干不了这个事 所以可以用cdq分治+AC自动机O(nlogn)解决 但是本题强制在线~~~ 我们还有一个工具,叫 ...

  4. CodeForces - 710F:String Set Queries (二进制分组 处理 在线AC自动机)

    ou should process m queries over a set D of strings. Each query is one of three kinds: Add a string ...

  5. Codeforces 710F - String Set Queries(AC 自动机)

    题面传送门 题意:强制在线的 AC 自动机. \(n,\sum|s|\leq 3\times 10^5\) 如果不是强制在线那此题就是道 sb 题,加了强制在线就不那么 sb 了. 这里介绍两种做法: ...

  6. PAT甲题题解-1050. String Subtraction (20)-水题

    #include <iostream> #include <cstdio> #include <string.h> #include <algorithm&g ...

  7. 《LeetBook》leetcode题解(8): String to Integer (atoi) [E]——正负号处理

    我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...

  8. LeetCode题解 #8 String to Integer (atoi)

    又是一道恶心的简单题. 一开始没想到这么多情况的,幸好LeetCode是个很人性化的oj,能让你知道你在哪个case上错了,否则一辈子都过不了. 考虑不周到只能一个个补了. 列举一下恶心的case / ...

  9. leetcode个人题解——#8 string to integer

    第八题 class Solution { public: int myAtoi(string str) { ; ; ; while(str[i] == ' ')i++; if (str[i] == ' ...

随机推荐

  1. Java面试题全集(上)转载

    Java面试题全集(上)   2013年年底的时候,我看到了网上流传的一个叫做<Java面试题大全>的东西,认真的阅读了以后发现里面的很多题目是重复且没有价值的题目,还有不少的参考答案也是 ...

  2. JAVA核心技术I---JAVA基础知识(集合set)

    一:集合了解 (一)确定性,互异性,无序性 确定性:对任意对象都能判定其是否属于某一个集合 互异性:集合内每个元素都是无差异的,注意是内容差异 无序性:集合内的顺序无关 (二)集合接口HashSet, ...

  3. openstack ovs实现vlan组网

    本文是配置文档,非说明文档,只讲配置,不讲原理. controller节点: 网卡信息:ens160 外网网卡 : ens192 数据网卡 /etc/neutron/plugins/ml2/ml2_c ...

  4. html 表格边线设置

    <table rules="all" style="margin-left: auto; margin-right: auto; margin-top: 50px; ...

  5. Kettle系列: kettle标准化trans模板

    =============================主控trans + sub trans 模式=============================针对一个具体的处理任务(比如增量加载一个 ...

  6. 'DataVisualization' does not exist in the namespace 'System.Web.UI'一例解决办法

    之前项目是vs2010 aspx项目,用vs2017打开后,非运行状态下有一行错误:CS0234 C# The type or namespace name 'DataVisualization' d ...

  7. Tomcat连接池配置与实现/JNDI

    方法一: 在Tomcat的conf/context.xml中配置在Tomcat\apache-tomcat-6.0.33\conf目录下的context.xml文件中配置默认值如下: <?xml ...

  8. JS算法练习四

    JS算法练习 1.将使用空格分隔单词使用驼峰命名连接起来: var str="HELLO world welcome to my hometown"; /*--先输入一个有空格分隔 ...

  9. oracle 窗口函数 (keep)

    看到很多人对于keep不理解,这里解释一下! Returns the row ranked first using DENSE_RANK2种取值:DENSE_RANK FIRSTDENSE_RANK  ...

  10. python 的基础 学习 第八天数据类型的补充 ,集合和深浅copy

    1,数据类型的补充: 元组()tuple,如果只有元素,并且没有逗号,此元素是什么数据类型,该表达式就是什么数据类型. tu = ('rwr') print(tu,type(tu)) tu = ('r ...