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. RocketMQ安装教程

    1.下载 http://mirror.bit.edu.cn/apache/rocketmq/ 2.安装 .tar.gz cd alibaba-rocketmq/bin chmod u+x * 3.配置 ...

  2. 基于spring的PropertySource类实现配置的动态替换

    public class ConfigPropertySource extends PropertySource<Properties> implements PriorityOrdere ...

  3. dubbo源码分析(一)-从xml到我们认识的Java对象

    项目中用的dubbo的挺多的,然后随着自己对dubbo的慢慢深入,自己也希望能够了解dubbo的底层实现,这半年来一直在看dubbo的源码,有点断断续续的,于是准备写一个dubbo源码系列的分析文章, ...

  4. \x 和 0x 的区别

    1.0x 表示整型数值 (十六进制) char c = 0x42; 表示的是一个数值(字母B对应的ASCII码——  66),可以认为等价于: int c = 0x42; 2.\x42用于字符表达,或 ...

  5. WINDOWS 端口查看

    查看Windows下所有使用的端口 netstat -ano 查看Windows下某一个特定的端口 netstat -ano | find "8080"   查看windows下所 ...

  6. Win10系列:VC++调用自定义组件2

    (2)C#调用WinRT组件 在解决方案资源管理器中右键点击解决方案图标,选择添加一个Visual C#的Windows应用商店的空白应用程序项目,并命名为FileCS.接着右键点击FileCS项目的 ...

  7. outline: none;

    outline: none:用在去掉某个选中后显示的外边框,(追求细节) http://www.w3school.com.cn/cssref/pr_outline.asp

  8. POJ 1035 Spell checker 字符串 难度:0

    题目 http://poj.org/problem?id=1035 题意 字典匹配,单词表共有1e4个单词,单词长度小于15,需要对最多50个单词进行匹配.在匹配时,如果直接匹配可以找到待匹配串,则直 ...

  9. 将自己的域名解析跳转到博客主页(GitHub中的gitpage跳转)

    最近突然迷上了博客,突然又突发奇想,将自己几个月前买的现在限制的域名拿来跳转到自己的csdn博客.经过一番研究,总结---- 把自己的购买的域名(比如我买的circleyuan.top)跳转到CSDN ...

  10. 第二章 使用unittest模块扩展功能测试

    2.1使用功能测试驱动开放一个最简单的应用 # functional_tests.py # -*- coding: utf-8 -*- from selenium import webdriver b ...