BZOJ3881 Divljak


解:对被包含的那些串建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的更多相关文章
- fail树
前置技能:AC自动机 假设我们有了一个AC自动机,然后在上面进行字符串匹配. 上面是一个有四个字符串的AC自动机(abcde.aacdf.cdf.cde),虚线是fail指针,实线是转移. 这是上一次 ...
- Noip前的大抱佛脚----赛前任务
赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...
- 【BZOJ3881】[Coci2015]Divljak fail树+树链的并
[BZOJ3881][Coci2015]Divljak Description Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操 ...
- 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序
3881: [Coci2015]Divljak Time Limit: 20 Sec Memory Limit: 768 MBSubmit: 508 Solved: 158[Submit][Sta ...
- 【bzoj3881】【Coci2015】Divljak
题解 对$S$集合ac建自动机,把$T_{i}$放在里面跑,记录路径上的所有节点并对它们在fail树上求到root的树链并: 这样就得到了$T_{i}$所有的子串: 动态将$T_{i}$加入直接用树状 ...
- BZOJ3881 : [Coci2015]Divljak
对Alice的所有串构造AC自动机,并建出Fail树 每当Bob添加一个串时,在AC自动机上走,每走到一个点,就把它到根路径上所有点的答案+1 需要注意的是每次操作,相同的点只能被加一次 所以在需要操 ...
- BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- 【bzoj3881】[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- BZOJ3881 Coci2015 Divljak fail树+差分
题目大意,给出两个字符串集合S和T,向T中添加字符串,查询S_i在T中有几个字符串出现过.一看这种多字符串匹配问题,我们联想到了AC自动机,做法就是,对于S集合我们建立一个AC自动机,建出fail树, ...
随机推荐
- vue-axios的application/x-www-form-urlencod的post请求无法解析参数
vue-axios的post会先将对象转为json然后再根据headers的设置再转一次格式,可以将参数先用qs.stringify()转一次再传输
- java.lang.Comparable 接口 详解
参考https://blog.csdn.net/itm_hadf/article/details/7432782 http://www.blogjava.net/jjshcc/archive/2011 ...
- 为linux主机增加file description
在benchmarked写的服务器的时候就遇到了too many file open 这个报错. 由于遇到过很多次了,所以知道应该是单机fd打满了. 首先来看看 机器最多支持多少fd cat /pro ...
- jQuery的each使用陷阱
注意:jQuery使用each()函数进行循环时发现return false不能阻止程序继续向下执行 原因如下: (1)开始还以为是jQuery的each()函数是异步执行的,所以导致出错,其实不是. ...
- How to install Lion on PC
open 'InstallESD.dmg' open '/Volumes/Mac OS X Install ESD/BaseSystem.dmg' rm '/Volumes/Mac OS X Base ...
- cookie的域,路径
Cookie 的路径以及 Cookie 域 cookie 路径 cookie 一般都是由于用户访问页面而被创建的,可是并不是只有在创建 cookie 的页面才可以访问这个cookie.在默认情况下,出 ...
- C语言学习IDE和基本程序结构
任何一门语言的学习,首先要有一个编辑器或集成开发工具IDE, 要不然代码都不知道写到什么地方.对于我这种小白来说,安装个IDE是最好不过的,因为C 语言也是编译语言,写完代码之后,要先编译才能运行,而 ...
- Nginx TSL/SSL优化握手性能
L:131
- 在idea中设置记住git的用户名和密码
在idea中设置记住git的用户名和密码 1.在项目根目录下执行以下git命令: git config --global credential.helper store 2.执行上述命令后,在idea ...
- mosquitto发布消息
./mosquitto_pub -t '$SYS/broker/clients/status/online' -m 1