题解-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] == ' ...
随机推荐
- CentOS7 上以 RPM 包方式安装 Oracle 18c 单实例
安装阿里云 YUM 源 https://opsx.alibaba.com/mirror?lang=zh-CN 一.安装Oracle数据库 1.安装 Oracle 预安装 RPM yum -y loca ...
- 用itext合并多个pdf文件【转】【补】
java代码 package c; import java.io.FileOutputStream; import java.io.IOException; import java.util.Arra ...
- Sublime Text 3 浅色主题
1.参考 如何优雅使用Sublime Text3(Sublime设置豆沙绿背景色和自定义主题) Fluidvision Inspiredgithub LightRays Mac 20Classic P ...
- 让Windows Server 2008r2 IIS7.5 ASP.NET 支持10万并发请求
由于之前使用的是默认配置,服务器最多只能处理5000个同时请求,今天下午由于某种情况造成同时请求超过5000,从而出现了上面的错误. 为了避免这样的错误,我们根据相关文档调整了设置,让服务器从设置上支 ...
- SQL Server进阶(六)表表达式--派生表、公用表表达式(CTE)、视图和内联表值函数
概述 表表达式是一种命名的查询表达式,代表一个有效地关系表.可以像其他表一样,在数据处理中使用表表达式. SQL Server支持四种类型的表表达式:派生表,公用表表达式,视图和内联表值函数. 为什么 ...
- CSS3 transform-origin 属性
<!DOCTYPE html> <html> <head> <style> #div1 { position: relative; height: 20 ...
- 前段js的各种弹出框
artDialog 首页 > 文档与示例 artDialog —— 经典的网页对话框组件,内外皆用心雕琢. 支持普通与 12 方向气泡状对话框 完善的焦点处理,自动焦点附加与回退 支持 ARIA ...
- matplotlib-2D绘图库学习目录
matplotlib的安装和 允许中文及几种字体 散点图 直线和点 子图 点的形状 条形图 堆叠条形图 直方图 颜色和样式字符串 饼状图 画多个图 画网格 线的形状 图例 坐标轴 画注释 ...
- C语言编程程序的内存如何布局
重点关注以下内容: C语言程序在内存中各个段的组成 C语言程序连接过程中的特性和常见错误 C语言程序的运行方式 一:C语言程序的存储区域 由C语言代码(文本文件)形成可执行程序(二进制文件),需要经过 ...
- react编译报错:Import in body of module; reorder to top import/first
原因是这样的: 我把一个组件分为三个文件, |—Home.jsx // 业务逻辑与html Home——|—Home.css // 样式 |—index.js // 引入Home.css ,再把Hom ...