显然是用AC自动机

先构建好AC自动机,当B中插入新的串时就在trie上跑,对于当前点,首先这个点所代表的串一定出现过,然后这个点指向的fail也一定出现过.那么我们把每个点fail当作父亲,建一棵fail树,那么到一个点一定会让fail树中这个点到根的路径所有点的答案+1.然后因为在同一个串中多次出现只算一次,那么就需要求这些到根的路径的并集.可以用树链剖分求区间交集做.

但这道题我们只用单点查询,区间修改,可以用树状数组做.因为是求交集,这里有一个trick就是把所有的点按dfs序排序,然后每个点到根+1,相邻的点的lca到根-1,就简单的求出了并集.

我们将区间修改单点查询转化为单点修改区间查询.那么一个点就只用查子树内的就行了.

具体可以看代码.修改的总点数不超过询问的串的总长,所以时间复杂度是O(nlogn)O(nlogn)O(nlogn)

lca是用树剖求的

CODE

#include<bits/stdc++.h>
using namespace std;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
template<class T>inline void read(T &res) {
char ch; int flg = 1; while(!isdigit(ch=getchar()))if(ch=='-')flg=-flg;
for(res=ch-'0';isdigit(ch=getchar());res=res*10+ch-'0'); res*=flg;
}
const int MAXN = 2000005;
const int C = 26;
int n, m, node[MAXN];
int tmr, dfn[MAXN], seq[MAXN], dep[MAXN], son[MAXN], sz[MAXN], top[MAXN], fa[MAXN];
int fir[MAXN], to[MAXN], nxt[MAXN], cnt;
inline void link(int u, int v) { to[cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt++; }
void dfs1(int x) {
dep[x] = dep[fa[x]] + 1; sz[x] = 1;
for(int v, i = fir[x]; ~i; i = nxt[i]) {
dfs1(v=to[i]), sz[x] += sz[v];
if(!(~son[x]) || sz[son[x]] < sz[v])
son[x] = v;
}
}
void dfs2(int x, int tp) {
top[x] = tp; seq[dfn[x]=++tmr] = x;
if(~son[x]) dfs2(son[x], tp);
for(int v, i = fir[x]; ~i; i = nxt[i])
if((v=to[i]) != son[x]) dfs2(v, v);
}
inline int lca(int x, int y) {
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
struct Aho_Corasick {
int ch[MAXN][C], fail[MAXN], tot, q[MAXN];
inline int insert(char *s) {
int r = 0, i = 0, indx;
while(*s) {
if(!ch[r][indx=(*s++)-'a'])
ch[r][indx] = ++tot;
r = ch[r][indx];
}
return r;
}
inline void build() {
int r = 0, head = 0, tail = 0;
fail[q[tail++]=r] = -1;
while(head < tail) {
r = q[head++];
for(int v, indx = 0; indx < C; ++indx)
if((v=ch[r][indx])) {
q[tail++] = v;
fail[v] = (r == 0 ? 0 : ch[fail[r]][indx]);
}
else ch[r][indx] = (r == 0 ? 0 : ch[fail[r]][indx]);
}
memset(fir, -1, sizeof fir);
memset(son, -1, sizeof son);
for(int i = 1; i <= tot; ++i) link(fa[i]=fail[i], i);
dfs1(0); dfs2(0, 0);
}
int T[MAXN];
inline void upd(int x, int val) {
while(x <= tmr) T[x] += val, x += x&-x;
}
inline int qsum(int x) { int re = 0;
while(x) re += T[x], x -= x&-x;
return re;
}
void modify(char *s) {
int r = 0, i = 0, indx, cur = 0;
while(*s) {
r = ch[r][indx=(*s++)-'a'];
q[++cur] = dfn[r];
}
sort(q + 1, q + cur + 1);
cur = unique(q + 1, q + cur + 1) - q - 1;
for(int i = 1; i <= cur; ++i) {
upd(q[i], 1);
if(i > 1) upd(dfn[lca(seq[q[i]], seq[q[i-1]])], -1);
}
}
}trie;
char s[MAXN];
int main() {
read(n);
for(int i = 1; i <= n; ++i)
scanf("%s", s), node[i] = trie.insert(s);
trie.build();
read(m);
int op, x;
while(m--) {
read(op);
if(op == 1) scanf("%s", s), trie.modify(s);
else read(x), x = node[x], printf("%d\n", trie.qsum(dfn[x]+sz[x]-1)-trie.qsum(dfn[x]-1));
}
}

BZOJ 3881[COCI2015]Divljak (AC自动机+dfs序+lca+BIT)的更多相关文章

  1. BZOJ 3881: [Coci2015]Divljak [AC自动机 树链的并]

    3881: [Coci2015]Divljak 题意:添加新文本串,询问某个模式串在多少种文本串里出现过 模式串建AC自动机,考虑添加一个文本串,走到的节点记录下来求树链的并 方法是按dfs序排序去重 ...

  2. bzoj 3881: [Coci2015]Divljak AC自动机

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3881 题解: 这道题我想出了三种做法,不过只有最后一种能过. 第一种: 首先我们把所有的 ...

  3. BZOJ-3881:Divljak (AC自动机+DFS序+树链求并+树状数组)

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

  4. BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )

    一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...

  5. BZOJ 3881: [Coci2015]Divljak

    3881: [Coci2015]Divljak Time Limit: 20 Sec  Memory Limit: 768 MBSubmit: 553  Solved: 176[Submit][Sta ...

  6. BZOJ2434[Noi2011]阿狸的打字机——AC自动机+dfs序+树状数组

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

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

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

  8. 【bzoj3881】[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组

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

  9. BZOJ 3881 [Coci2015]Divljak(AC自动机+树状数组)

    建立AC自动机然后,加入一个串之后考虑这个串的贡献.我们把这个串扔到AC自动机里面跑.最后对经过每一个点到的这个点在fail树的根的路径上的点有1的贡献.求链的并,我们把这些点按DFS序排序,然后把每 ...

随机推荐

  1. 吉首大学2019年程序设计竞赛(重现赛)- A SARS病毒 (矩阵,欧拉降幂)

    题目链接:https://ac.nowcoder.com/acm/contest/992/A 题意:求出长度为n的字符串个数,字符串由A.C.G.T组成,其中A和C必须成对出现. 思路:我们规定:   ...

  2. Min swaps to sort array

    Given an array with distinct numbers, return an integer indicating the minimum number of swap operat ...

  3. memcached命令行、Memcached数据导出和导入

    1.memcached命令行 telnet 127.0.0.1 11211set key2 0 30 2abSTOREDget key2VALUE key2 0 2abEND  如: set key3 ...

  4. Eclipse中 coverage as 测试代码覆盖率

    eclipse 版本: Version: 2019-06 (4.12.0)Build id: 20190614-1200 绿色:代码被执行过黄色:代码部分被执行过红色:代码没有被执行过 引用: htt ...

  5. double write 双写

    Oracle 8KB Postgresql 8KB MySQL Innodb 16KB buffer page block首先,要DML数据,需要先把page读取到index page中,之后对内存中 ...

  6. git安装配置相关

    Git是一个分布式的版本控制系统,最初由Linus Torvalds编写,用作Linux内核代码的管理.在推出后,Git在其它项目中也取得了很大成功,尤其是在Ruby社区中.目前,包括Rubinius ...

  7. linux内核编程入门 hello world

    注意: Makefile 文件的命名注意M需要大写,否则会报错. 在Makefile文件中make命令前应为tab制表符. 下文转载至:https://blog.csdn.net/bingqing07 ...

  8. pycharm连接mysql是出现Connection to orm02@127.0.0.1 failed. [08001] Could not create connection to database server. Attempted reconnect 3 times. Giving up.

    下面这个问题反正我是遇到了,也是难为我好几天,于是我决定发一个教程出来给大家看看!希望能帮助你们 原因: 可能是数据库的版本与本机装的驱动不匹配导致的, 解决方案一: 在 url 后面街上一句 因为笔 ...

  9. Codeforces 1244D. Paint the Tree

    传送门 首先如果某个点的度数大于 $2$ 那么显然无解 然后考虑点的度数小于等于 $2$ 的情况 发现其实是一条链 一旦确定了链开头的两个点,后面的点的颜色都可以通过之前的点推出 所以直接枚举即可 # ...

  10. mysql java jdbc 如何 update select

    2019年8月6日17:28:07 sql 不知道怎么写,也没去查,因为需求可能中途需要修改值,有点麻烦 直接用jdbc实现. 查询出来的值,直接根据update条件更新,写在一个方法里 public ...