题解-Codeforces710F String Set Queries
咕了好久没更博客,最近得知可以去冬眠营玩耍,还可以搭顺风车回广州过年
(最近做到的比较有意思的题目:bzoj3958、hihocoder1419)
Problem
题目概要:维护一个字符串集合,要求支持:加字符串、删字符串和查询当前所有已加入且未被删除的字符串在给出模板串中出现的次数(操作数&字符串总长\(\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的更多相关文章
- 【Codeforces710F】String Set Queries (强制在线)AC自动机 + 二进制分组
F. String Set Queries time limit per test:3 seconds memory limit per test:768 megabytes input:standa ...
- 【CF710F】String Set Queries(二进制分组,AC自动机)
[CF710F]String Set Queries(二进制分组,AC自动机) 题面 洛谷 CF 翻译: 你有一个字符集合\(D\),初始为空, 有三种操作: 往\(D\)中加入一个串:从\(D\)中 ...
- CF710F String Set Queries
CF710F String Set Queries 支持字符串的插入和删除...SAM也干不了这个事 所以可以用cdq分治+AC自动机O(nlogn)解决 但是本题强制在线~~~ 我们还有一个工具,叫 ...
- 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 ...
- Codeforces 710F - String Set Queries(AC 自动机)
题面传送门 题意:强制在线的 AC 自动机. \(n,\sum|s|\leq 3\times 10^5\) 如果不是强制在线那此题就是道 sb 题,加了强制在线就不那么 sb 了. 这里介绍两种做法: ...
- PAT甲题题解-1050. String Subtraction (20)-水题
#include <iostream> #include <cstdio> #include <string.h> #include <algorithm&g ...
- 《LeetBook》leetcode题解(8): String to Integer (atoi) [E]——正负号处理
我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...
- LeetCode题解 #8 String to Integer (atoi)
又是一道恶心的简单题. 一开始没想到这么多情况的,幸好LeetCode是个很人性化的oj,能让你知道你在哪个case上错了,否则一辈子都过不了. 考虑不周到只能一个个补了. 列举一下恶心的case / ...
- leetcode个人题解——#8 string to integer
第八题 class Solution { public: int myAtoi(string str) { ; ; ; while(str[i] == ' ')i++; if (str[i] == ' ...
随机推荐
- 在.NET程序中实现HttpServer功能
亲爱的下午茶 博客园 首页 新随笔 联系 订阅 管理 随笔-6 文章-0 评论-10 在.NET程序中实现HttpServer功能 最近在实现一个可视化数据解析工具,需要在Wpf程序中实 ...
- 谈谈关于PHP连接数据库的两种方法(PDO&Mysqli)
前言:在我们之前学习sql语句的时候都是停留在黑窗口的,怎样才能让mysql与程序代码发生联系呢?此时PDO和Mysqli应运而生,为了解决这个问题 (一)开启其中(pdo或者mysqli)的php扩 ...
- mysql创建用户与pymsql模块
mysql 创建用户及增删改查 创建mysql 用户 with grant option 表示用户不存在自主创建 grant [ select ……,insert ……| all ] on 库名.表名 ...
- 安装 ArcGISAPI31forSilverlight an i/o error occured while installing a file错误解决
安装ArcGISAPI31forSilverlight出现“an i/o error occured while installing a file……”主要是这个文件可能已经损坏了,如此,你在用到该 ...
- SpringBoot系列: 使用 flyway 管理数据库版本
Flyway 和 Liquibase 都是 Java 项目中常用的 DB migration 工具, 从使用简便性看,Flyway 比 Liquibase 更简单, 从 github 的 star ...
- [转载]SpringBoot系列: SpringMVC 参数绑定注解解析
本文转载自 https://www.cnblogs.com/morethink/p/8028664.html, 作者写得非常好, 致谢! SpringMVC 参数绑定注解解析 本文介绍了用于参数绑 ...
- PS 使用笔记 - PS 让工作台适应 当前图层
1. PS 让工作台适应 当前图层 选中图层 打开 [图像]=>[裁切] 勾选以下,确定即可
- Metaprogramming
Metaprogramming https://en.wikipedia.org/wiki/Metaprogramming 元编程, 是一种编程技术, 制造的计算机程序,具有这种能力, 对待程序为他们 ...
- 新闻类App顶部菜单栏封装
概述 最近有一个需求,类似今日头条顶部的菜单栏.唯一区别是需要带可移动的下划线.网上查找资料,发现解决方案大部分是用UIScrollView实现.下方VC控制用UICollectionView.这样可 ...
- Java SE之正则表达式一:概述
正则表达式 概念 定义:符合一定规则的表达式 作用:用于专门操作字符串 特点:用于一些特定的符号表示代码的操作,这样就简化了长篇的程序代码 好处:可以简化对字符串的复杂操作 弊端:符号定义越多,正则越 ...