ou should process m queries over a set D of strings. Each query is one of three kinds:

  1. Add a string s to the set D. It is guaranteed that the string s was not added before.
  2. Delete a string s from the set D. It is guaranteed that the string s is in the set D.
  3. 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.

Input

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

Input
5
1 abc
3 abcabc
2 abc
1 aba
3 abababc
Output
2
2
Input
10
1 abc
1 bcd
1 abcd
3 abcd
2 abcd
3 abcd
2 bcd
3 abcd
2 abc
3 abcd
Output
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自动机)的更多相关文章

  1. Codeforces 710F - String Set Queries(AC 自动机)

    题面传送门 题意:强制在线的 AC 自动机. \(n,\sum|s|\leq 3\times 10^5\) 如果不是强制在线那此题就是道 sb 题,加了强制在线就不那么 sb 了. 这里介绍两种做法: ...

  2. Codeforces 710F String Set Quries

    题意 维护一个字符串的集合\(D\), 支持3种操作: 插入一个字符串\(s\) 删除一个字符串\(s\) 查询一个字符串\(s\)在\(D\)中作为子串出现的次数 强制在线 解法 AC自动机+二进制 ...

  3. CodeForces 710F 强制在线AC自动机

    题目链接:http://codeforces.com/contest/710/problem/F 题意:维护一个集合,集合要求满足三种操作. 1 str:向集合插入字符串str(保证不会插入之前已经插 ...

  4. 【Codeforces710F】String Set Queries (强制在线)AC自动机 + 二进制分组

    F. String Set Queries time limit per test:3 seconds memory limit per test:768 megabytes input:standa ...

  5. 【CF710F】String Set Queries(二进制分组,AC自动机)

    [CF710F]String Set Queries(二进制分组,AC自动机) 题面 洛谷 CF 翻译: 你有一个字符集合\(D\),初始为空, 有三种操作: 往\(D\)中加入一个串:从\(D\)中 ...

  6. 【CF 710F】String Set Queries

    在校内OJ上A了,没有加强制在线的东西..不放链接了. 这道题题意是维护一个字符串集合,支持三种操作: 1.加字符串 2.删字符串 3.查询集合中的所有字符串在给出的模板串中出现的次数 操作数\(m ...

  7. CF710F String Set Queries

    CF710F String Set Queries 支持字符串的插入和删除...SAM也干不了这个事 所以可以用cdq分治+AC自动机O(nlogn)解决 但是本题强制在线~~~ 我们还有一个工具,叫 ...

  8. HDU 6166 Senior Pan(多校第九场 二进制分组最短路)

    题意:给出n个点和m条有向边(有向边!!!!我还以为是无向查了半天),然后给出K个点,问这k个点中最近的两点的距离 思路:比赛时以为有询问,就直接丢了,然后这题感觉思路很棒,加入把所有点分成起点和终点 ...

  9. codeforces 1217E E. Sum Queries? (线段树

    codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...

随机推荐

  1. CSS:font-family常用字体中英文对照

    CSS:font-family常用字体中英文对照如下: 推荐网址:https://www.cnblogs.com/EnSnail/p/6792853.html 微软雅黑: Microsoft YaHe ...

  2. Python3+telnetlib实现telnet客户端

    一.程序要点说明 python实现telnet客户端的六个关键问题及其答案是: 使用什么库实现telnet客户端----telnetlib 怎么连接主机----两种方法,一种是在实例化时传入ip地址连 ...

  3. xinetd黑/白名单配置教程(以telnet为例)

    对于诸如telnet等托管于xinetd的服务,当请求到来时由于是通过xinetd进行通知,所以可以直接在xinetd上配置白名单允许和拒绝哪些ip连接服务. 本文主要参考xinetd.conf的ma ...

  4. Kali安装教程(VMWare)

    1.下载镜像及相关 1.1下载镜像文件 下载链接:https://www.kali.org/downloads/ 选择自己需要的版本下载,根据经验先下载种子文件(torrent)再用迅雷下载网速是最有 ...

  5. 最佳加法表达式(dp)

    题目描述: 有一个由1..9组成的数字串.问如果将m个加 号插入到这个数字串中,在各种可能形成的 表达式中,值最小的那个表达式的值是多少 (本题只能用于整数) 解题思路: 假定数字串长度是n,添完加号 ...

  6. JavaScript中如何对一个对象进行深度clone

    <!doctype html><html><head><meta charset="utf-8"><title>深克隆& ...

  7. Fiddler系列教程1:初识Http协议抓包工具

    1. Fiddler简介 Fiddler是用一款使用C#编写的http协议调试代理工具.它支持众多的http调试任务,能够记录并检查所有你的电脑和互联网之间的http通讯,可以设置断点,查看所有的“进 ...

  8. Java 算法 概念汇总

    编程面试的10大算法概念汇总   以下是在编程面试中排名前10的算法相关的概念,我会通过一些简单的例子来阐述这些概念.由于完全掌握这些概念需要更多的努力,因此这份列表只是作为一个介绍.本文将从Java ...

  9. day32 信号量 事件 管道 进程池

    今日主要内容: 1.管道(Pipe) 数据接收一次就没有了 2.事件(Event) 3.基于事件的进程通信 4.信号量(Semaphore) 5. 进程池(重点) 6.进程池的同步方法和异步方法 7. ...

  10. tomcat版本对应jee版本等信息

    可以参考官方: http://tomcat.apache.org/whichversion.html http://www.bubuko.com/infodetail-674892.html