【CF710F】String Set Queries(二进制分组,AC自动机)
【CF710F】String Set Queries(二进制分组,AC自动机)
题面
洛谷
CF
翻译:
你有一个字符集合\(D\),初始为空,
有三种操作:
往\(D\)中加入一个串;从\(D\)中删除一个串;给定一个串\(S\),询问\(D\)中的串在\(S\)中总共出现了多少次。
题解
询问显然就是将\(S\)放在所有\(D\)构成的\(AC\)自动机上跑。
所以我们需要一种方法,可以动态的支持\(AC\)自动机的插入以及删除。
先考虑删除,这个很好办,我们可以维护两个\(AC\)自动机,一个记录插入,一个记录删除,将串在两个上面分别跑再做差就好了。这样子删除也变成了插入。
那么如何插入?
我们对于串二进制分组,因为串和串之间是独立的,所以可以对于每一组的串建立一个\(AC\)自动机,合并块的时候直接重构\(AC\)自动机就好了。
写起来很爽啊。我又回到了C++STL选手???string真好用
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define MAX 300300
#define pb push_back
struct Node{int son[26],fail,v;}t[MAX];
int St[MAX],top;
int NewNode(){return St[top--];}
void Insert(int u,string s)
{
for(int i=0,l=s.length();i<l;++i)
{
if(!t[u].son[s[i]-97])t[u].son[s[i]-97]=NewNode();
u=t[u].son[s[i]-97];
}
t[u].v+=1;
}
void Del(int rt)
{
if(!rt)return;
for(int i=0;i<26;++i)
Del(t[rt].son[i]),t[rt].son[i]=0;
t[rt].fail=t[rt].v=0;St[++top]=rt;
}
struct Group
{
vector<string> p;int tot,rt;
void insert(string s){p.pb(s);++tot;}
void clear(){Del(rt);rt=NewNode();p.clear();tot=0;}
void Build()
{
Del(rt);rt=NewNode();
for(int i=0;i<tot;++i)Insert(rt,p[i]);
queue<int> Q;t[rt].fail=rt;
for(int i=0;i<26;++i)
if(t[rt].son[i])Q.push(t[rt].son[i]),t[t[rt].son[i]].fail=rt;
while(!Q.empty())
{
int u=Q.front();Q.pop();
for(int i=0;i<26;++i)
if(t[u].son[i])
{
int p=t[u].fail,v=t[u].son[i];
while(p!=rt&&!t[p].son[i])p=t[p].fail;
if(t[p].son[i])t[v].fail=t[p].son[i];
else t[v].fail=rt;
Q.push(v);
t[v].v+=t[t[v].fail].v;
}
}
}
int Query(string s)
{
int ret=0,u=rt;
for(int i=0,l=s.length();i<l;++i)
{
int c=s[i]-97;
if(t[u].son[c])u=t[u].son[c];
else
{
int p=t[u].fail;
while(p!=rt&&!t[p].son[c])p=t[p].fail;
if(t[p].son[c])u=t[p].son[c];
else u=rt;
}
ret+=t[u].v;
}
return ret;
}
}A[20],B[20];
int tp1,tp2;
void Insert(string s)
{
++tp1;A[tp1].clear();A[tp1].insert(s);
while(tp1>1&&A[tp1].tot==A[tp1-1].tot)
{
for(int i=0;i<A[tp1].tot;++i)A[tp1-1].insert(A[tp1].p[i]);
A[tp1--].clear();
}
A[tp1].Build();
}
void Delete(string s)
{
++tp2;B[tp2].clear();B[tp2].insert(s);
while(tp2>1&&B[tp2].tot==B[tp2-1].tot)
{
for(int i=0;i<B[tp2].tot;++i)B[tp2-1].insert(B[tp2].p[i]);
B[tp2--].clear();
}
B[tp2].Build();
}
int Query(string s)
{
int ret=0;
for(int i=1;i<=tp1;++i)ret+=A[i].Query(s);
for(int i=1;i<=tp2;++i)ret-=B[i].Query(s);
return ret;
}
int m,opt;
string s;
int main()
{
ios::sync_with_stdio(false);
for(int i=1;i<MAX;++i)St[++top]=i;
cin>>m;
while(m--)
{
cin>>opt>>s;
if(opt==1)Insert(s);
if(opt==2)Delete(s);
if(opt==3)cout<<Query(s)<<endl;
}
return 0;
}
【CF710F】String Set Queries(二进制分组,AC自动机)的更多相关文章
- CF710F String Set Queries
CF710F String Set Queries 支持字符串的插入和删除...SAM也干不了这个事 所以可以用cdq分治+AC自动机O(nlogn)解决 但是本题强制在线~~~ 我们还有一个工具,叫 ...
- Codeforces963C Frequency of String 【字符串】【AC自动机】
题目大意: 给一个串s和很多模式串,对每个模式串求s的一个最短的子串使得这个子串中包含至少k个该模式串. 题目分析: 均摊分析,有sqrt(n)种长度不同的模式串,所以有关的串只有msqrt(n)种. ...
- ZOJ3784 String of Infinity 高大上的AC自动机 数据原来这么水啊!不算输入输出只有5-7行
找给定s集合里面word全部是同一个字符的,这样的word有几个,如果数量<m就yes,否则就no.#include<iostream> #include<cstring> ...
- 模板汇总——AC自动机
AC自动机 模板题 HDU-2222 Keywords Search #include<bits/stdc++.h> using namespace std; #define LL lon ...
- AC自动机
AC自动机,全称Aho-Corasick自动机.如果没记错的话好像就是前缀自动机. 其实AC自动机就是KMP上树的产物.理解了KMP,那AC自动机应该也是很好理解的. 与KMP类似,AC自动机也是扔一 ...
- 【Codeforces710F】String Set Queries (强制在线)AC自动机 + 二进制分组
F. String Set Queries time limit per test:3 seconds memory limit per test:768 megabytes input:standa ...
- 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 ...
- CF710F-String Set Queries【AC自动机,二进制分组】
正题 题目链接:https://www.luogu.com.cn/problem/CF710F 题目大意 \(T\)次操作 往集合中加入一个字符串 往集合中删除一个字符串 给出一个模式串求出现的集合里 ...
- Codeforces 710F - String Set Queries(AC 自动机)
题面传送门 题意:强制在线的 AC 自动机. \(n,\sum|s|\leq 3\times 10^5\) 如果不是强制在线那此题就是道 sb 题,加了强制在线就不那么 sb 了. 这里介绍两种做法: ...
随机推荐
- svn树冲突的解决方法
树冲突 就是开发人员移动.重命名.删除一个文件或文件夹,而另一名开发人员也对它们进行了移动.重命名.删除或者仅仅是修改时就会发生树冲突.有很多种不同的情形可以导致树冲突,而且不同的情形需要不同的步骤来 ...
- 【SIKIA计划】_06_Unity2D游戏开发-拾荒者笔记
[新增分类]Animations 动画——Animation——AnimatorControllerPrefabs 预制 [素材导入]unitypackage 素材包Sprites Editor 编辑 ...
- 【坚持】Selenium+Python学习记录 DAY10
2018/05/31-2018/06/1 [官方文档](https://www.jetbrains.com/help/pycharm/set-up-a-git-repository.html) 通过p ...
- python实现简单线性回归
之前推导了一元线性回归和多元线性回归,今天就用python来实现一下一元线性回归 先看下之前推导的结果 , 第一种是用循环迭代的计算方法.这里的x,y是numpy中的array类型 def su ...
- PHP 伪协议
1.file:// file://用于访问本地文件系统,不受allow_url_fopen影响 <?php include($_GET['file']); ?> 2.http:// GET ...
- 团队博客作业Week4 --- 学霸网站--NABC
1.需求(Need) 伴随着经济的发展,科学技术取得了飞速的发展,互联网在各行各业的发展中取得了广泛的应用.随着这些事物的发展,我们每个人都会接触到相当庞大的数据.如何在这些数据中找到自己需要的,如何 ...
- 转载 intellij IDEA 使用体验 (本人感觉它的使用是一种趋势)
从去年开始转java以来,一直在寻找一款趁手的兵器,eclipse虽然是很多java程序员的首选,但是我发现一旦安装了一些插件,workspace中的项目达到数10个以后,经常崩溃,实在影响编程的心情 ...
- Task 4.2 求一个矩阵的最大子矩阵的和
任务:输入一个二维整形数组,数组里有正数也有负数.二维数组中连续的一个子矩阵组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n). (1)设计思想:把二维矩阵分解成 ...
- mvc 路由配置-学习
MapRoute(RouteCollection, String, String) 映射指定的URL路由. 'Declaration <ExtensionAttribute> _ Publ ...
- Internet History, Technology and Security (Week5.1)
Week5 The Transport layer is built on the Internetwork layer and is what makes our network connectio ...