题解-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] == ' ...
随机推荐
- Problems found loading plugins: Plugin "GlassFish Integration" was not loaded: required plugin "Java EE: EJB, JPA, Servlets" is disabled.
idea启动报错:并且无法部署web项目 Problems found loading plugins: Plugin "GlassFish Integration" was no ...
- HTML第四耍 超链接标签
1.HTML 超链接(链接) 一.HTML 超链接 HTML中使用超级链接与网络上的另一个文档相连.几乎可以在所有的网页中找到链接.点击链接可以从一张页面跳转到另一张页面. 超链接可以是一个字,一个词 ...
- MVC实用架构设计(三)——EF-Code First(1):Repository,UnitOfWork,DbContext
前言 终于到EF了,实在不好意思,最近有点忙,本篇离上一篇发布已经一个多星期了,工作中的小迭代告一段落,终于有点时间来继续我们的架构设计了,在这里先对大家表示歉意. 其实这段时间我并不是把这个系列给忘 ...
- Redis基本概念、基本使用与单机集群部署
1. Redis基础 1.1 Redis概述 Redis是一个开源.先进的key-value存储,并用于构建高性能.可扩展的应用程序的完美解决方案. Redis从它的许多竞争继承了三个主要特点: ...
- ZooKeeper基础CRUD操作
==============================Curator Java 客户端 CRUD 使用==============================Curator 是 Apache ...
- 【八】Spring Cloud Config
一.分布式系统面临的--配置问题 微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的力度相对较小,因此系统中会出现大量的服务.由于每个服务都需要必要的配置信息才能运行,所以一套集中式的.动 ...
- bzoj 1531 Bank notes 多重背包/单调队列
多重背包二进制优化终于写了一次,注意j的边界条件啊,疯狂RE(还是自己太菜了啊啊)最辣的辣鸡 #include<bits/stdc++.h> using namespace std; in ...
- luogu P3312 [SDOI2014]数表
传送门 我们看要求的东西\[\sum_{i=1}^{n}\sum_{j=1}^{m}[\sigma(gcd(i,j))\le a]\sigma(gcd(i,j))\] 然而\(\le a\)比较烦,可 ...
- Utterance-Wise Recurrent Dropout And Iterative Speaker Adaptation For Robust Monaural Speech Recognition
单声道语音识别的逐句循环Dropout迭代说话人自适应 WRBN(wide residual BLSTM network,宽残差双向长短时记忆网络) [2] J. Heymann, L. Dr ...
- Python 10 协程,异步IO,Paramiko
本节内容 Gevent协程 异步IO Paramiko 携程 协程,又称为微线程,纤程(coroutine).是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文 ...