BZOJ 3881[COCI2015]Divljak (AC自动机+dfs序+lca+BIT)
显然是用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)的更多相关文章
- BZOJ 3881: [Coci2015]Divljak [AC自动机 树链的并]
3881: [Coci2015]Divljak 题意:添加新文本串,询问某个模式串在多少种文本串里出现过 模式串建AC自动机,考虑添加一个文本串,走到的节点记录下来求树链的并 方法是按dfs序排序去重 ...
- bzoj 3881: [Coci2015]Divljak AC自动机
题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3881 题解: 这道题我想出了三种做法,不过只有最后一种能过. 第一种: 首先我们把所有的 ...
- BZOJ-3881:Divljak (AC自动机+DFS序+树链求并+树状数组)
Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. “2 x” ...
- BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )
一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...
- BZOJ 3881: [Coci2015]Divljak
3881: [Coci2015]Divljak Time Limit: 20 Sec Memory Limit: 768 MBSubmit: 553 Solved: 176[Submit][Sta ...
- BZOJ2434[Noi2011]阿狸的打字机——AC自动机+dfs序+树状数组
题目描述 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小 ...
- 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. ...
- BZOJ 3881 [Coci2015]Divljak(AC自动机+树状数组)
建立AC自动机然后,加入一个串之后考虑这个串的贡献.我们把这个串扔到AC自动机里面跑.最后对经过每一个点到的这个点在fail树的根的路径上的点有1的贡献.求链的并,我们把这些点按DFS序排序,然后把每 ...
随机推荐
- Oracle的基本操作-序列的使用
序列:默认从1开始,一次递增,主要用来给主键赋值使用 create sequence s_person; select s_person.nextval from dual; --dual是一张虚表, ...
- VIM 介绍
gedit a.txt 是一个图形界面的文本编辑器. 需要安装图形界面才会有. nano a.txt 也是一样的 vi 是一种文本界面的编辑器. vim 是 vimsual interfa ...
- Synchronized与Lock的区别与应用场景
转载. https://blog.csdn.net/fly910905/article/details/79765381 同步代码块,同步方法,或者是用java提供的锁机制,我们可以实现对共享资源变量 ...
- Java笔记1: 输入输出与变量常量
输入方法 nextLine 以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符. 可以获得空白的一串字符. import java.util.Scanner; pu ...
- PAT B1002 写出这个数(20)
AC代码 #include <cstdio> #include <iostream> #include <cstring> using namespace std; ...
- python虚拟环境的的使用
基于创建虚拟环境 virtualenv 安装 pip3 install virtualenv 通过virtulaenv创建虚拟环境 virtualenv luffycity --python=C:\P ...
- Qt5.8.0编译QtMqtt库并使用该库连接有人云的例子
一 编译QtMqtt库Qt5.10才官方支持MQTT,但我用的Qt版本是5.8.0 Mingw_32BIT, 为了在Qt5.8.0上添加MQTT支持,需要自己编译源码 步骤: (1) git clon ...
- Centos系统修改docker默认网络参数
刚Yum装完发现是没有网上所说的/etc/default/docker文件的,自己vim后其实也是不生效的. 因为Docker的systemd启动脚本(/usr/lib/systemd/system/ ...
- dev gridview表格按钮
固定列的位置 添加按钮控件位置,使用buttonEdit 添加按钮 按钮属性设置 按钮设置后的效果 //注册按钮事件 this.ribtndata.ButtonClick += new DevExpr ...
- 【js】面向对象学习资料
1.面向对象模式: https://m.jb51.net/article/74549.htm 2.面向对象基础篇 http://www.cnblogs.com/chiangchou/p/js-oop1 ...