要点

  • 显然ac自动机的板子就可以暴力一下答案了
  • 为了优化时间复杂度,考虑套路fail树的dfs序。发现本题需要当前这个尾点加上所有祖先点的个数,考虑使用树状数组差分一下,在父点+1,在子树后-1,每次询问前缀和即可
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
using namespace std; typedef long long ll;
const int N = 1e6 + 5, maxk = 1e5 + 5; int n, k, pos[maxk], in[maxk];
string s, t; struct FenwickTree {
ll F[N]; void Modify(int x, int val) {
for (; x < N; x += x&-x)
F[x] += val;
} ll Query(int x) {
ll res = 0;
for (; x; x -= x&-x)
res += F[x];
return res;
}
}bit; struct Aho_Corasick_Automaton {
int ch[N][26];//Trie树的转移
//int val[N];//根据题意赋值。有值则意味着某子串末尾
int fail[N];//失配,转移到别的树枝接着找
int sz;//注意这个板子sz一定是要从1开计
vector<int> adj[N];//用于fail树
int dfn[N], Time, size[N]; void insert(string s, int id) {//Trie的插入
int len = s.length(), now = 0; for (int i = 0; i < len; i++){
int c = s[i] - 'a';
if (!ch[now][c]) {
sz++;
memset(ch[sz], 0, sizeof ch[sz]);
//val[sz] = 0;
ch[now][c] = sz;
}
now = ch[now][c];
}
//val[now] = id;
pos[id] = now;
} void getfail(){
queue<int> Q;
for (int i = 0; i < 26; i++)
if (ch[0][i]) {
adj[0].emplace_back(ch[0][i]);
fail[ch[0][i]] = 0, Q.push(ch[0][i]);//第二层指向根
}
while (!Q.empty()){
int u = Q.front(); Q.pop();
for (int i = 0; i < 26; i++)
if (ch[u][i]) {
adj[ch[fail[u]][i]].emplace_back(ch[u][i]);
fail[ch[u][i]] = ch[fail[u]][i], Q.push(ch[u][i]);//指向其他枝上同样的字母
}
else ch[u][i] = ch[fail[u]][i];//使得find时半路突然失配时还能一下拐回去
}
} void dfs(int u) {
dfn[u] = ++Time;
size[u] = 1;
for (int v : adj[u]) {
dfs(v);
size[u] += size[v];
}
} int find(string T){
int len = T.length(), now = 0;
ll res = 0; for (int i = 0; i < len; i++){
now = ch[now][T[i] - 'a'];
res += bit.Query(dfn[now]);
// for (int t = now; t; t = fail[t])//事实上这是一个不断缩短后缀的过程
// if (val[t]) res++;
}
return res;
}
}ac; int calc(string t) {
stringstream ss(t);
int x; ss >> x;
return x;
} int main() {
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> k;
for (int i = 1; i <= k; i++) {
cin >> s;
ac.insert(s, i);
in[i] = 1;
}
ac.getfail();
ac.dfs(0);
for (int i = 1; i <= k; i++) {
int id = pos[i];
bit.Modify(ac.dfn[id], 1);
bit.Modify(ac.dfn[id] + ac.size[id], -1);
} for (int i = 0; i < n; i++) {
cin >> t;
char x = t[0]; t.erase(0, 1);
if (x == '+') {
int v = calc(t);
if (!in[v]) {
int id = pos[v];
bit.Modify(ac.dfn[id], 1);
bit.Modify(ac.dfn[id] + ac.size[id], -1);
in[v] = 1;
}
} else if (x == '-') {
int v = calc(t);
if (in[v]) {
int id = pos[v];
bit.Modify(ac.dfn[id], -1);
bit.Modify(ac.dfn[id] + ac.size[id], 1);
in[v] = 0;
}
} else {
cout << ac.find(t) << '\n';
}
}
}

Codeforces 163E(ac自动机、树状数组)的更多相关文章

  1. 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树

    正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...

  2. 【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序

    [题意]阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写 ...

  3. Codeforces 587F - Duff is Mad(根号分治+AC 自动机+树状数组)

    题面传送门 第一眼看成了 CF547E-- 话说 CF587F 和 CF547E 出题人一样欸--还有另一道 AC 自动机的题 CF696D 也是这位名叫 PrinceOfPersia 的出题人出的- ...

  4. Codeforces 547E - Mike and Friends(AC 自动机+树状数组)

    题面传送门 好久每做过 AC 自动机的题了--做几个题回忆一下罢 AC 自动机能够解决多串匹配问题,注意是匹配,碰到前后缀的问题那多半不在 AC 自动机能解决的范围内. 在初学 AC 自动机的时候相信 ...

  5. CoderForces 163E e-Government(AC自动机+树状数组维护fail树的dfs序)

    E. e-Government time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...

  6. BZOJ2434: [Noi2011]阿狸的打字机(AC自动机 树状数组)

    Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4140  Solved: 2276[Submit][Status][Discuss] Descript ...

  7. BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  8. HDU 6096 String(AC自动机+树状数组)

    题意 给定 \(n\) 个单词,\(q\) 个询问,每个询问包含两个串 \(s_1,s_2\),询问有多少个单词以 \(s_1\) 为前缀, \(s_2\) 为后缀,前后缀不能重叠. \(1 \leq ...

  9. bzoj 2434 AC自动机+树状数组

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3493  Solved: 1909[Submit][Sta ...

  10. [NOI2011]阿狸的打字机 --- AC自动机 + 树状数组

    [NOI2011] 阿狸的打字机 题目描述: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现, ...

随机推荐

  1. nodejs && apidoc

    1. 安装nodejs      http://www.nodejs.org      源码编译      configure —prefix=/usr/local/nodejs      make ...

  2. 网络编程学习笔记-MAC地址和IP地址的关系

    简单地说:ip地址是服务商给你的,mac地址是你的网卡物理地址. 一.IP地址 对于IP地址,相信大家都很熟悉,即指使用TCP/IP协议指定给主机的32位地址.IP地址由用点分隔开的4个8八位组构成, ...

  3. HihoCoder1670 : 比赛日程安排([Offer收割]编程练习赛41)(模拟)

    描述 H国编程联赛中有N只队伍,编号1~N. 他们计划在2018年一共进行M场一(队)对一(队)的比赛. 为了让参赛队员能得到充分的休息,联赛组委会决定:每支队伍连续两场比赛之间至少间隔一天.也就是如 ...

  4. 「LuoguP4995」「洛谷11月月赛」 跳跳!(贪心

    题目描述 你是一只小跳蛙,你特别擅长在各种地方跳来跳去. 这一天,你和朋友小 F 一起出去玩耍的时候,遇到了一堆高矮不同的石头,其中第 ii 块的石头高度为 h_ihi​,地面的高度是 h_0 = 0 ...

  5. May we can use Turbolinks or Pjax in our web apps

    Turbolinks[1]: Turbolinks makes following links in your web application faster.Instead of letting th ...

  6. 选择排序(java)

    选择排序的思想是:内外两层循环,第一层循环从第一个数开始到倒数第一个数, 第二层循环从上一层的数开始, 与上一层循环的数比较,如果小于则交换位置. 代码如下: public class SelectS ...

  7. Http协议-报文

    2013的双12即将到来,网上购物是大家所熟悉的.看中小米电视时,可以先下订单然后再付款,电商根据订单将小米电视正确安全的送达给我们.包裹包含电视的基本信息及电视的使用说明书,使我们能够初步的了解它的 ...

  8. Adding In-App Purchase to your iOS and OS X Applications

    Adding In-App Purchase to your iOS and OS X Applications In-App Purchase allows you to sell addition ...

  9. TypeScript完全解读(26课时)_汇总贴

    ECMAScript 6 入门:http://es6.ruanyifeng.com/ 官网:http://www.typescriptlang.org/ 中文网:https://www.tslang. ...

  10. Android图片压缩框架-Tiny 集成

    为了简化对图片压缩的调用,提供最简洁与合理的api压缩逻辑,对于压缩为Bitmap根据屏幕分辨率动态适配最佳大小,对于压缩为File优化底层libjpeg的压缩,整个图片压缩过程全在压缩线程池中异步压 ...