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 s to the set D. It is guaranteed that the string s was not added before.
- Delete a string s from the set D. It is guaranteed that the string s is in the set D.
- For the given string s find the number of occurrences of the strings from the set D. If some string p from D has several occurrences in s you should count all of them.
Note that you should solve the problem in online mode. It means that you can't read the whole input at once. You can read each query only after writing the answer for the last query of the third type. Use functions fflush in C++ and BufferedWriter.flush in Java languages after each writing in your program.
The first line contains integer m (1 ≤ m ≤ 3·105) — the number of queries.
Each of the next m lines contains integer t (1 ≤ t ≤ 3) and nonempty string s — the kind of the query and the string to process. All strings consist of only lowercase English letters.
The sum of lengths of all strings in the input will not exceed 3·105.
Output
For each query of the third kind print the only integer c — the desired number of occurrences in the string s.
Examples
5
1 abc
3 abcabc
2 abc
1 aba
3 abababc
2
2
10
1 abc
1 bcd
1 abcd
3 abcd
2 abcd
3 abcd
2 bcd
3 abcd
2 abc
3 abcd
3
2
1
0
题意:三种操作,1,给集合S加串;2,删串;3,询问子串在S出现的个数。 强制在线。
思路:如果不是强制在线,我们可以先对所有要加的串,建立AC自动机,然后用AC自动机+DFS序+线段树离线操作。
这里要求在线,主要问题就是如何高效的维护AC自动机的fail,我们用二进制来分块;使得每个串最多合并log次。。。
二进制分组:每次加串,就在尾巴建立一个字典树,集合大小为1; 如果集合大小和前面的相同,就合并到前面。 合并完后,对其建立AC自动机,得到fail和sum。
对于强制在线的题,这是个不错的方式,复杂度O(NlogN),不过常数有点大。 我们也可以用分块的思想去做,O(NsqrtN)。
(至于为什么网上都是加和删分别构造AC自动机,不太明白,感觉没必要。
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
char c[maxn]; int len;
struct ACAM{
int cnt,ch[maxn][],fail[maxn],ac[maxn][];
int rt[maxn],num[maxn],sum[maxn],tot[maxn],T;
ACAM(){
cnt=; T=;
rep(i,,) rt[i]=num[i]=;
}
queue<int>que;
void add(int &Now,int L,int opt)
{
if(!Now) Now=++cnt;
if(L==len+){ tot[Now]+=opt; return ;}
add(ch[Now][c[L]-'a'],L+,opt);
}
void build(int d) {
que.push(d); fail[d]=d; sum[d]=;
for (int i=;i<;i++) ac[d][i]=d;
while(!que.empty()) {
int u=que.front();que.pop();
sum[u]=sum[fail[u]]+tot[u];
for (int i=;i<;i++) if (ch[u][i]) {
int v=ch[u][i];
que.push(v); fail[v]=ac[fail[u]][i]; ac[u][i]=v;
} else ac[u][i]=ac[fail[u]][i];
}
}
int merge(int x,int y)
{
if(!x||!y) return x^y;
tot[x]+=tot[y];
rep(i,,)
ch[x][i]=merge(ch[x][i],ch[y][i]);
return x;
}
void insert(int opt)
{
T++; add(rt[T],,opt); num[T]=;
while(num[T]==num[T-]){
rt[T-]=merge(rt[T-],rt[T]);
rt[T]=; num[T-]+=num[T];
num[T]=; T--;
}
build(rt[T]);
}
ll query()
{
ll res=;
rep(i,,T) {
if(!rt[i]) continue;
int Now=rt[i];
rep(j,,len){
Now=ac[Now][c[j]-'a'];
res+=sum[Now];
}
}
return res;
}
}a;
int main()
{
int N,opt;
scanf("%d",&N);
rep(i,,N){
scanf("%d%s",&opt,c+);
len=strlen(c+);
if(opt==) a.insert();
else if(opt==) a.insert(-);
else printf("%lld\n",a.query()),fflush(stdout);
}
return ;
}
两个,分别表示加和删:
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
char c[maxn]; int len;
struct ACAM{
int cnt,ch[maxn][],fail[maxn],ac[maxn][];
int rt[maxn],num[maxn],sum[maxn],tot[maxn],T;
ACAM(){
cnt=; T=;
rep(i,,) rt[i]=num[i]=;
}
queue<int>que;
void add(int &Now,int L)
{
if(!Now) Now=++cnt;
if(L==len+){ tot[Now]++; return ;}
add(ch[Now][c[L]-'a'],L+);
}
void build(int d) {
que.push(d); fail[d]=d; sum[d]=;
for (int i=;i<;i++) ac[d][i]=d;
while(!que.empty()) {
int u=que.front();que.pop();
sum[u]=sum[fail[u]]+tot[u];
for (int i=;i<;i++) if (ch[u][i]) {
int v=ch[u][i];
que.push(v); fail[v]=ac[fail[u]][i]; ac[u][i]=v;
} else ac[u][i]=ac[fail[u]][i];
}
}
int merge(int x,int y)
{
if(!x||!y) return x^y;
tot[x]+=tot[y];
rep(i,,)
ch[x][i]=merge(ch[x][i],ch[y][i]);
return x;
}
void insert()
{
T++; add(rt[T],); num[T]=;
while(num[T]==num[T-]){
rt[T-]=merge(rt[T-],rt[T]);
rt[T]=; num[T-]+=num[T];
num[T]=; T--;
}
build(rt[T]);
}
ll query()
{
ll res=;
rep(i,,T) {
if(!rt[i]) continue;
int Now=rt[i];
rep(j,,len){
Now=ac[Now][c[j]-'a'];
res+=sum[Now];
}
}
return res;
}
}a,b;
int main()
{
int N,opt;
scanf("%d",&N);
rep(i,,N){
scanf("%d%s",&opt,c+);
len=strlen(c+);
if(opt==) a.insert();
else if(opt==) b.insert();
else printf("%lld\n",a.query()-b.query()),fflush(stdout);
}
return ;
}
CodeForces - 710F:String Set Queries (二进制分组 处理 在线AC自动机)的更多相关文章
- Codeforces 710F - String Set Queries(AC 自动机)
题面传送门 题意:强制在线的 AC 自动机. \(n,\sum|s|\leq 3\times 10^5\) 如果不是强制在线那此题就是道 sb 题,加了强制在线就不那么 sb 了. 这里介绍两种做法: ...
- Codeforces 710F String Set Quries
题意 维护一个字符串的集合\(D\), 支持3种操作: 插入一个字符串\(s\) 删除一个字符串\(s\) 查询一个字符串\(s\)在\(D\)中作为子串出现的次数 强制在线 解法 AC自动机+二进制 ...
- CodeForces 710F 强制在线AC自动机
题目链接:http://codeforces.com/contest/710/problem/F 题意:维护一个集合,集合要求满足三种操作. 1 str:向集合插入字符串str(保证不会插入之前已经插 ...
- 【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\)中 ...
- 【CF 710F】String Set Queries
在校内OJ上A了,没有加强制在线的东西..不放链接了. 这道题题意是维护一个字符串集合,支持三种操作: 1.加字符串 2.删字符串 3.查询集合中的所有字符串在给出的模板串中出现的次数 操作数\(m ...
- CF710F String Set Queries
CF710F String Set Queries 支持字符串的插入和删除...SAM也干不了这个事 所以可以用cdq分治+AC自动机O(nlogn)解决 但是本题强制在线~~~ 我们还有一个工具,叫 ...
- HDU 6166 Senior Pan(多校第九场 二进制分组最短路)
题意:给出n个点和m条有向边(有向边!!!!我还以为是无向查了半天),然后给出K个点,问这k个点中最近的两点的距离 思路:比赛时以为有询问,就直接丢了,然后这题感觉思路很棒,加入把所有点分成起点和终点 ...
- codeforces 1217E E. Sum Queries? (线段树
codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...
随机推荐
- PAT-GPLT训练集 L1-043 阅览室
PAT-GPLT训练集 L1-043 阅览室 注意:连续的S和E才算一次借还 代码: #include<iostream> #include<cstdio> using nam ...
- LY.JAVA面向对象编程.内部类
2018-07-18 10:14:48 /* 内部类概述: 把类定义在其他类的内部,这个类就被称为内部类. 举例:在类A中定义了一个类B,类B就是内部类. 内部的访问特点: A:内部类可以直接访问外部 ...
- learning scala read from file
scala读文件: example: scala> import scala.io.Sourceimport scala.io.Source scala> var inputFile ...
- .net core 在扩展中使用接口实例之IServiceProvider
在.net core 2.0中,我们使用的对象实例大多数都是通过构造函数依赖注入进来的,但那是在一般的类中使用. 如果需要在静态/扩展类中使用某些服务类的对象实例,可以使用如下方式: 1.新建一个Se ...
- IIS设置上传文件大小限制
单位为字节. 500*1024*1024=524288000
- java有关构造器的面试题详解
1,编译器只会提供自动提供一个默认的无参数的构造函数 2,如果程序员没有给类A没有提供构造函数,则编译器会自动提供一个默认的无参数的构造函数,如果用户提供了自己的构造函数,则编译器就不在提供默认的无参 ...
- turtle
画一组同切圆 输入 import turtle turtle.color('red') turtle.circle(30) turtle.circle(60) turtle.circle(90) tu ...
- DevExpress WinForms使用教程:WinForms Sunburst控件
[DevExpress WinForms v18.2下载] DevExpress WinForms v18.2中包含了一个新的WinForms组件 - WinForms Sunburst,它旨在帮助开 ...
- Core Java 面经
1 面向对象的特征有哪些方面? (1)抽象,抽象就是忽略与当前目标无关的部分,抽象包含两个方面,一是过程抽象,一是数据 (2)继承,是Java中允许和鼓励类重用的思想的体现,, 它提供了一种方式,可 ...
- powerdesigner远程连接数据库
1. dabatase-->configure connections 2.新建连接 3.配置TNS连接测试 4.出现异常及处理 Could not Initialize JavaVM! 出现这 ...