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. nodejs sequelize 对应数据库操作符的定义

    const Op = Sequelize.Op [Op.and]: {a: } // 且 (a = 5) [Op.or]: [{a: }, {a: }] // (a = 5 或 a = 6) [Op. ...

  2. AIX安装JDK1.7教程

    1.下载 下载链接(下载需要登录IBM账号):https://www.ibm.com/developerworks/java/jdk/aix/service.html#i1 由于jdk版本AIX操作系 ...

  3. 剑指 offer 面试题31 连续子数组的最大和(动态规划)

    求连续子数组的最大和 题目描述 给定一个整形数组,有正数也有负数,数组中连续一个或多个组成一个子数组,求所有子数组的和的最大值,要求时间复杂度为O(n); 测试用例 给定数组 {1,-2,3,10,- ...

  4. Zabbix3.4.7监控windows进程

    1.首先,找到要监控进程的主机 创建新的监控项 然后应用集选择processes,点击添加,此处是以zabbix_agentd.exe为例添加 2. 为此监控项添加触发器 注意触发器表达式的编写,上面 ...

  5. Android 音视频深入 四 录视频MP4(附源码下载)

    本篇项目地址,名字是<录音视频(有的播放器不能放,而且没有时长显示)>,求star https://github.com/979451341/Audio-and-video-learnin ...

  6. unity中把一个图片切割成两个UI图片

    1.在unity3D的Project视图下选中需要更改的图片,将图片的Texture Type更改为Sprite (2D and UI),点击Apply即可.操作如图所示: 2.完成步骤一,点击App ...

  7. MySQL字符集与校对

    一.什么是字符集与校对 1.字符集与校对 字符集是指一种从二进制编码到某种字符符号的映射. 校队是指一组用于某个字符集的配许规则. 2.utf8与utf8mb4 标准的UTF-8字符集编码是可以使用1 ...

  8. nginx入门示例(二)

    nginx使用域名访问 (Tip)      nginx目录解析 conf/nginx.conf   #主要的配置文件目录 html      #nginx的默认发布目录,部署完后 网站会在这个目录 ...

  9. selenium(六)Headless Chrome/Firefox--PhantomJS停止支持后,使用无界面模式。

    简介: 以前都用PhantomJS来进行无界面模式的自动化测试,或者爬取某些动态页面. 但是最近selenium更新以后,'Selenium support for PhantomJS has bee ...

  10. DevExpress ASP.NET Bootstrap Controls v18.2新功能详解(二)

    行业领先的.NET界面控件2018年第二次重大更新——DevExpress v18.2日前正式发布,本站将以连载的形式为大家介绍新版本新功能.本文将介绍了DevExpress ASP.NET Boot ...