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树, ...
随机推荐
- Kafka-Flume-elasticsearch
a1.sources = kafkaSource a1.channels = memoryChannel a1.sinks = elasticsearch a1.sources.kafkaSource ...
- 4面向对象(OOP)
学习线路 初学: 熟悉语法 进阶: 1.23种设计模式 2.6中开发原则 高级: 1.优化 2.架构 3.安全 概念 类:一类具有相同特性的事物的抽象描述,用一个java类表示. 成员变量:抽取的属性 ...
- 新版本macos无法安装mysql-python包
在更新了macos之后就发现无法正确安装python-mysql包了. 上网查阅了一下应该是c库或者osx的基础工具变动带来的问题.看到很多解决办法说使用pymysql,拜托我问的是如何安装pytho ...
- MySQL磁盘写入策略以及数据安全性的相关参数
转载自:http://blog.itpub.net/22664653/viewspace-1063134/ innodb_flush_log_at_trx_commit和sync_binlog ...
- JQ判断在不同分辨率电脑下使用不同的banner尺寸
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Apache的commons工具类
package cn.zhou; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileU ...
- springboot+jpa+mysql+swagger整合
Springboot+jpa+MySQL+swagger整合 创建一个springboot web项目 <dependencies> <dependency> < ...
- WPF中如何调整TabControl的大小,使其跟随Window的大小而改变?
多年不写技术博客,手生的很,也不知道大家都关注什么,最近在研究Wpf及3d模型的展示,碰到很多问题,这个是最后一个问题,写出来小结一下...... WPF中如何调整TabControl的大小,使其跟随 ...
- react用构造函数创建组件
有两种方法,一种是通过构造函数创建,一种是通过class创建 1.构造函数创建组件 用function+组件名的方式创建,创建好了,在render里面以标签的形式一丢就可以啦!但是这种方式必须要ret ...
- 11.ingress服务
kubernetes 的service服务我们提到过.service 可以用nodePort的方式和调用公有云LBAAS服务 来对于集群外的client提供服务访问,但是service是工作的osi ...