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

(最近做到的比较有意思的题目: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. Windows下的包管理工具-Scoop

    关于scoop的介绍 https://www.jianshu.com/p/bb0ba62b519c https://blog.csdn.net/fcymk2/article/details/86653 ...

  2. Dubbo服务的运行方式

    1.使用Servlet容器运行(Tomcat.Jetty)等 ---不可取 缺点:增加复杂性(端口,管理) 浪费资源(内存) 2.自建Main方法类来运行(Spring容器) ---不建议(本地调试可 ...

  3. C语言:使用结构体和指针函数实现面向对象思想(OO编程)

    原文:https://www.linuxidc.com/Linux/2016-12/138789.htm 有关:<C语言:过年回家 发现只有我没有对象> 一.基础研究 观察如下两个程序a. ...

  4. 【1】[leetcode-124] 二叉树中的最大路径和

    (没做出来,典型题目重要) 二叉树中的最大路径和(hard) 给定一个非空二叉树,返回其最大路径和. 本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列.该路径至少包含一个节点,且不一定经 ...

  5. ssm的架构及整合说明

    SSM,即 SpringMVC.Spring 与 MyBatis 三个框架 它们在三层架构中所处的位置是不同的,即它们在三层架构中的功能各不相同,各司其职 SpringMVC:作为 View 层的实现 ...

  6. c# 三种传参方式 in,out,ref

    in:默认方式,传值不返回 out:不传值 但是会返回新值给予传参对象 ref:传存储地址,所以传参前必须赋值初始化,传值后的运算结果直接作用在传参上 Out和ref的效果差不多

  7. springBoot----aop--整合日志相关

    springBoot整合日志相关 1:新建log4j.properties文件 : log4j.properties: #log4j.rootLogger=CONSOLE,info,error,DEB ...

  8. springBoot的事物管理

    springBoot的事物管理 1:springBoot 整合单数据源事物: Spring Boot 使用事务非常简单,首先使用注解 @EnableTransactionManagement 开启事务 ...

  9. 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、Git/SVN)

    一. 各类概念和指令介绍 1. NVM (1).  全称:Node Version Manager,是一款针对Nodejs的版本管理工具,由于Node的版本很多,很多时候我要需要依赖多个版本,并且要求 ...

  10. webpack3.x版本实战案例【基础配置篇】(一)

    本文旨在通过一个一个实战例子来学习webpack如何配置,更加深入的学习webpack在实战项目中如何配置. 我们学习哪些配置呢? [基础配置] 打包JS 编译ES6 编译typeScript 打包公 ...