解:对被包含的那些串建AC自动机。

每次加一个串,就在AC自动机上面跑,可知能够跑到一些节点。

这些节点都是一些前缀的形式,我们跳fail树就是跳后缀,这样就能够得到所有能匹配的子串。

我们分别对AC自动机中的每个串计算答案。

就是要求一些节点到根路径的并集,并对其权值 + 1。查询就查对应节点。

然后有个trick就是lca处 - 1,节点处 + 1,然后求子树和。、

 #include <bits/stdc++.h>

 const int N = , M = ;

 struct Edge {
int nex, v;
}edge[M]; int tp; int tr[M][], fail[M], tot = , n, ed[N];
std::queue<int> Q;
char str[N];
int e[M], pos[M], siz[M], num, ST[M << ][], d[M], stk[M], pw[M << ], top, pos2[M << ], num2; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} void DFS(int x) {
pos[x] = ++num;
pos2[x] = ++num2;
ST[num2][] = x;
siz[x] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
d[y] = d[x] + ;
DFS(y);
ST[++num2][] = x;
siz[x] += siz[y];
}
return;
} inline void prework() {
for(int i = ; i <= num2; i++) {
pw[i] = pw[i >> ] + ;
}
for(int j = ; j <= pw[num2]; j++) {
for(int i = ; i + ( << j) - <= num2; i++) {
if(d[ST[i][j - ]] < d[ST[i + ( << (j - ))][j - ]])
ST[i][j] = ST[i][j - ];
else
ST[i][j] = ST[i + ( << (j - ))][j - ];
}
}
/*for(int j = 0; j <= pw[num2]; j++) {
printf("j = %d : ", j);
for(int i = 1; i + (1 << j) - 1 <= num2; i++) {
printf("%d ", ST[i][j]);
}
puts("");
}*/
return;
} inline bool cmp(const int &a, const int &b) {
return pos[a] < pos[b];
} inline int lca(int x, int y) {
//printf("lca : %d %d = ", x, y);
x = pos2[x]; y = pos2[y];
if(x > y) std::swap(x, y);
int t = pw[y - x + ];
if(d[ST[x][t]] < d[ST[y - ( << t) + ][t]])
return ST[x][t];
//{ printf("%d \n", ST[x][t]); return ST[x][t]; }
else
return ST[y - ( << t) + ][t];
//{ printf("%d \n", ST[y - (1 << t) + 1][t]); return ST[y - (1 << t) + 1][t]; }
} namespace ta {
int ta[M];
inline void add(int x, int v) {
for(int i = x; i <= tot; i += i & (-i)) {
ta[i] += v;
}
return;
}
inline int getSum(int x) {
int ans = ;
for(int i = x; i >= ; i -= i & (-i)) {
ans += ta[i];
}
return ans;
}
inline int ask(int l, int r) {
return getSum(r) - getSum(l - );
}
} inline void insert(int id) {
int n = strlen(str), p = ;
for(int i = ; i < n; i++) {
int f = str[i] - 'a';
if(!tr[p][f]) {
tr[p][f] = ++tot;
}
p = tr[p][f];
}
ed[id] = p;
return;
} inline void BFS() {
Q.push();
fail[] = ;
while(!Q.empty()) {
int x = Q.front();
Q.pop();
for(int f = ; f < ; f++) {
if(!tr[x][f]) continue;
int y = tr[x][f], j = fail[x];
while(j != && !tr[j][f]) {
j = fail[j];
}
if(x != && tr[j][f]) {
j = tr[j][f];
}
fail[y] = j;
Q.push(y);
}
}
return;
} inline void add() {
int n = strlen(str), p = ;
top = ;
for(int i = ; i < n; i++) {
int f = (str[i]) - 'a';
while(p != && !tr[p][f]) p = fail[p];
if(tr[p][f]) p = tr[p][f];
if(p > ) stk[++top] = p;
}
if(!top) return;
std::sort(stk + , stk + top + , cmp);
top = std::unique(stk + , stk + top + ) - stk - ;
for(int i = ; i <= top; i++) {
ta::add(pos[stk[i]], );
if(i < top) {
int z = lca(stk[i], stk[i + ]);
ta::add(pos[z], -);
}
}
return;
} inline int ask(int x) {
return ta::ask(pos[x], pos[x] + siz[x] - );
} int main() {
int m;
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%s", str);
insert(i);
}
BFS();
///
for(int i = ; i <= tot; i++) {
add(fail[i], i);
//printf("add %d %d \n", fail[i], i);
}
d[] = ;
DFS();
prework(); scanf("%d", &m);
for(int i = , f, x; i <= m; i++) {
scanf("%d", &f);
if(f == ) {
scanf("%s", str);
add();
}
else {
scanf("%d", &x);
printf("%d\n", ask(ed[x]));
}
}
return ;
}

MLE代码

BZOJ3881 Divljak的更多相关文章

  1. fail树

    前置技能:AC自动机 假设我们有了一个AC自动机,然后在上面进行字符串匹配. 上面是一个有四个字符串的AC自动机(abcde.aacdf.cdf.cde),虚线是fail指针,实线是转移. 这是上一次 ...

  2. Noip前的大抱佛脚----赛前任务

    赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...

  3. 【BZOJ3881】[Coci2015]Divljak fail树+树链的并

    [BZOJ3881][Coci2015]Divljak Description Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操 ...

  4. 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序

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

  5. 【bzoj3881】【Coci2015】Divljak

    题解 对$S$集合ac建自动机,把$T_{i}$放在里面跑,记录路径上的所有节点并对它们在fail树上求到root的树链并: 这样就得到了$T_{i}$所有的子串: 动态将$T_{i}$加入直接用树状 ...

  6. BZOJ3881 : [Coci2015]Divljak

    对Alice的所有串构造AC自动机,并建出Fail树 每当Bob添加一个串时,在AC自动机上走,每走到一个点,就把它到根路径上所有点的答案+1 需要注意的是每次操作,相同的点只能被加一次 所以在需要操 ...

  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. BZOJ3881 Coci2015 Divljak fail树+差分

    题目大意,给出两个字符串集合S和T,向T中添加字符串,查询S_i在T中有几个字符串出现过.一看这种多字符串匹配问题,我们联想到了AC自动机,做法就是,对于S集合我们建立一个AC自动机,建出fail树, ...

随机推荐

  1. Eclipse在写java时的BUG

    要把这个关掉

  2. Day 4-9 subprocess模块

    我们经常需要通过Python去执行一条系统命令或脚本,系统的shell命令是独立于你的python进程之外的,每执行一条命令,就是发起一个新进程,通过python调用系统命令或脚本的模块在python ...

  3. 关于 ajax

    1.type 提交类型 get /post 2.async 默认true 异步 3.cache 默认 true 读取缓存 false不读取缓存  会在请求后面 添加一个时间戳 https://www. ...

  4. APP test

    在讲APP测试之前,先讲一下,目前APP的操作系统以及APP相关基础知识. 一.APP基础知识 1.操作系统# 现在移动端的操作系统主流的分为两种:(1)安卓系统 (2)IOS系统. 2.安卓系统# ...

  5. composer 出现You are running Composer with SSL/TLS protection disabled.

    开启php的ssl开启 composer config -g -- disable-tls false

  6. thinkphp视图中插入php代码

    性别: <?php if($item['sex'] == 1):?> 男 <?php else:?> 女 <?php endif;?> 错误:<?php ec ...

  7. case when 空值判断

    在对数据库进行查询时,遇到了一个问题:查询结果中的某一列需要判断另一列是否为空的来确定值,自然就想到了case when,于是写出了下面的SQL(其他部分省略): (case date when nu ...

  8. LodopJS代码模版的加载和赋值

    Lodop模版有两种方法,一种是传统的JS语句,可以用JS方法里的eval来执行,一种是文档式模版,是特殊格式的base64码,此篇博文介绍JS模版的加载和赋值.两种模版都可以存入一下地方进行调用,比 ...

  9. react 自我小计

    1.react中的方法调用,在onClick事件中不需要加小括号. <button onClick={this.show}>方法的调用</button> show(){ con ...

  10. hdu-6165(tarjan+topusort)

    题意:一个有向图,无自环,无重边,让你判断这个图内的任意两点是否有路: 解题思路:首先,判断两个点是否可达一般用出入度来判断,如果在拓扑排序中同时有两个及以上入度同时为零的点,那么,这些入度的为零的点 ...