题意

维护一个字符串的集合$D$, 支持3种操作:

  1. 插入一个字符串$s$
  2. 删除一个字符串$s$
  3. 查询一个字符串$s$在$D$中作为子串出现的次数

强制在线

解法

AC自动机+二进制分组

二进制分组

二进制分组是一种用 (套用) 离线方法解决要求强制在线问题的分块技巧. 我第一次见到它是在2013年IOI国家集训队许昊然的论文<浅谈数据结构题的几个非经典解法>中. 满足修改操作对询问的贡献独立, 修改操作之间互不影响效果 (其实前后两句说的是同一件事) 的数据结构题, 都可以采用二进制分组算法.

原理

修改操作序列按二进制分组. 所谓"二进制", 指的是将长为$n$的修改序列按原顺序分成$k$组 (实际上是对时间分块), $k$为$n$的二进制表示中1的数目, 第$i$组的长度为第$i$个1的权重 (2的幂), 每组用一个数据结构维护. 例如, 长为10的操作序列将分成两组长度分别为 8 (1~8), 2 (9~10). 当修改序列的长度从$n$变成$n+1$时, 暴力重建变化的那些组, 不难看出需要重建的修改序列的总长度为lowbit($n+1$).

不难看出, 这个题目所涉及的操作与询问满足上述条件.

实现

二进制分组的框架:

设修改序列为vector<operation> s, 数据结构序列为 vector<structure> t.

  1. pop_back: 将过期的分组从队尾弹出
for(x=S.size(); x && lowbit(x)<lowbit(S.size()+1); t.pop_back(), x-=lowbit(x));
s.push_back(cur_op); // 将当前修改操作加进修改序列
  1. push_back: 将新建分组入队
structure cur;    // 初始化为空
for(int i=s.size()-lowbit(s.size()); i<s.size(); i++) // 0-indexed
cur.insert(s[i]);
t.push_back(cur);

Implementation

本题中除了用到二进制分组意外, 还有一个巧妙的转化:

分别维护插入和删操作形成的AC-自动机组 X, Y (即把删除操作也当作插入操作), 最后结果就是在X中查询的答案减去在Y中查询的答案.

#include <bits/stdc++.h>
using namespace std; const int N{1<<19}, M{1<<10};
typedef long long LL; vector<string> s; struct node{
int ch[26], fail, last, cnt;
bool f;
}; int lowbit(int x){
return x&-x;
} queue<int> que; struct AC{
using trie = vector<node>;
vector<trie> g; //group
vector<string> s; //string buffer void insert(const string &t){
for(int x=s.size(); x && lowbit(x)<lowbit(s.size()+1); g.pop_back(), x-=lowbit(x)); //error-prone
g.push_back({});
auto &cur=*g.rbegin();
cur.push_back({});
s.push_back(t); for(int i=s.size()-lowbit(s.size()); i<s.size(); i++){
int u=0;
for(auto &x:s[i]){
// int &v=cur[u].ch[x-'a']; //error
// do not use a reference to an object stored in a vector or any other dynamically allocated container,
// when it is under construction.
if(!cur[u].ch[x-'a']){
cur[u].ch[x-'a']=cur.size();
cur.push_back({});
}
u=cur[u].ch[x-'a'];
}
cur[u].cnt=1;
cur[u].f=true;
} for(int i=0; i<26; i++){
int u=cur[0].ch[i];
if(u) que.push(u);
} for(; que.size(); ){
int u=que.front();
que.pop();
for(int i=0; i<26; i++){
int &v=cur[u].ch[i]; //error-prone
if(v){ //v is a new node
que.push(v);
int &fail=cur[v].fail, &last=cur[v].last;
fail=cur[cur[u].fail].ch[i];
last=cur[fail].f ? fail : cur[fail].last;
cur[v].cnt+=cur[last].cnt;
// alternative: cur[v].cnt+=cur[fail].cnt;
}
else v=cur[cur[u].fail].ch[i];
}
}
} LL match(const string &t){
LL res=0;
for(auto &cur: g){
int u=0;
for(auto &x: t){ // no need to add a const before auto
u=cur[u].ch[x-'a'];
res+=cur[u].cnt;
}
}
return res;
}
}a, b; int main(){
int m, tail=0;
cin>>m;
string x;
for(int i=0, t; i<m; i++){
cin>>t>>x;
if(t==1){
a.insert(x);
}
else if(t==2){
b.insert(x);
}
else cout<<a.match(x)-b.match(x)<<endl;
}
}

代码中注释了我当时犯的一个不易察觉的错误.

Codeforces 710F String Set Quries的更多相关文章

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

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

  2. 【Codeforces 710F】String Set Queries

    Codeforces 710 F 思路:KMP学的还是不过关啊... 按照字符串的长度分类,如果长度大于\(\sqrt{n}\)的就扔到什么地方等待查询,否则就扔进trie里面. 对于查询,我们先在t ...

  3. 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 ...

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

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

  5. Codeforces 799D. String Game 二分

    D. String Game time limit per test:2 seconds memory limit per test:512 megabytes input:standard inpu ...

  6. Codeforces - 828C String Reconstruction —— 并查集find()函数

    题目链接:http://codeforces.com/contest/828/problem/C C. String Reconstruction time limit per test 2 seco ...

  7. CodeForces 159c String Manipulation 1.0

    String Manipulation 1.0 Time Limit: 3000ms Memory Limit: 262144KB This problem will be judged on Cod ...

  8. CodeForces 779D. String Game(二分答案)

    题目链接:http://codeforces.com/problemset/problem/779/D 题意:有两个字符串一个初始串一个目标串,有t次机会删除初始串的字符问最多操作几次后刚好凑不成目标 ...

  9. Codeforces 110B-Lucky String(技能)

    B. Lucky String time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

随机推荐

  1. 《Web开发过滤Javascript、HTML的方法》

    JavaScript过滤方法: 第一种方案:使用 htmlspecialchars 函数转换特殊字符和使用 nl2br 函数插入一些必要的 <br /> 标签. $comment = &l ...

  2. 解决mysql卸载后无法从新安装,卡在最后一步的问题

    mysql服务出现问题往往是最麻烦的,往往需要重装,而重装很多人卸不干净残留文件,更加装不上.在下就遇到这个问题.重装mysql到最后一步时卡在了最后一步的第二条上 解决办法就是卸载后删注册表+删数据 ...

  3. Undefined symbols for architecture arm64:

    1. 没有往项目中导入静态库(.a 文件)需要的 framework. 2.拖到项目中的静态库不支持arm64(或其他)指令集  这种情况没遇到过 一般都是第一种情况.

  4. IOS之Objective-C学习 策略模式

    对于策略模式,我个人理解策略模式就是对各种规则的一种封装的方法,而不仅仅是对算法的封装与调用而已.与工厂模式中简单工厂有点类似,但是比简单工厂更有耦合度,因为策略模式以相同的方法调用所有的规则,减少了 ...

  5. jQuery 上传头像插件Jcrop的实例

    兼容:ie6+,FF,chrome等 示例图: CSS:     说明:图像比例为110:135     下载包里有 jquery.Jcrop.css          .jc-demo-box{po ...

  6. RSS阅读器

    RSS阅读器(Really Simple Syndication)是一种软件/程序,实质都是为了方便地读取RSS和Atom文档.大概就是实现了订阅式阅读,推送用户感兴趣的新闻,博客等(比如等某位博主更 ...

  7. linux 做gw(nat)详细配置

                          linux 做企业网关gw(nat)详细配置   最近因为公司的路由器老化导致上网时断时续,上半小时网就断一次网,为此我头疼不已,本着为公司节约成本的宗旨, ...

  8. 利用联合双边滤波或引导滤波进行升采样(Upsampling)技术提高一些耗时算法的速度。

    这十年来,在图像处理领域提出了很多新的图像分析和处理方法,包括是自动的以及一些需要有人工参与的,典型的比如stereo depth computations.image colorization.to ...

  9. AndroidStudio中make Project、clean Project、Rebuild Project的区别

    1.Make Project:编译Project下所有Module,一般是自上次编译后Project下有更新的文件,不生成apk. 2.Make Selected Modules:编译指定的Modul ...

  10. jenkins 入门教程(下)

    接上回继续学习jenkins,这次主要来看一些疑难杂症: 一.yum install安装方式 除了直接java -jar jenkins.war方式,还可以用yum安装,这种方式下提供了更多的可配置选 ...