3881: [Coci2015]Divljak

Time Limit: 20 Sec  Memory Limit: 768 MB
Submit: 508  Solved: 158
[Submit][Status][Discuss]

Description

Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的。
接下来会发生q个操作,操作有两种形式:
“1 P”,Bob往自己的集合里添加了一个字符串P。
“2 x”,Alice询问Bob,集合T中有多少个字符串包含串S_x。(我们称串A包含串B,当且仅当B是A的子串)
Bob遇到了困难,需要你的帮助。

Input

第1行,一个数n;
接下来n行,每行一个字符串表示S_i;
下一行,一个数q;
接下来q行,每行一个操作,格式见题目描述。

Output

对于每一个Alice的询问,帮Bob输出答案。

Sample Input

3
a
bc
abc
5
1 abca
2 1
1 bca
2 2
2 3

Sample Output

1
2
1

HINT

【数据范围】
1 <= n,q <= 100000;
Alice和Bob拥有的字符串长度之和各自都不会超过 2000000;
字符串都由小写英文字母组成。

Source

鸣谢 Dzy

Solution

首先这个题得利用fail树的性质....

这种给出一个串在给出的一坨串中出现次数或者是否出现过,这样显然是利用fail树...

然后就是把路径上的点变成1,询问有多少个1...这个可以利用树状数组维护DFS序得到...

然后这个题就是先把Alice的串建AC自动机并且建出fail树...

然后每得到Bob的串,就在fail树上相应的点上+1,但是直接+1会有重复,所以先对所有的点排序,然后直接将+1标记打在节点上,并对相邻节点的LCA上打上-1标记,这样询问就转化成求子树和。

数据规模比较大,倍增LCA会被卡..

其实正解应该建虚树...这样的复杂度还是比较玄学....建虚树应该是比较保险的方法.

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
inline int read()
{
int x=; char ch=getchar();
while (ch<'' || ch>'') ch=getchar();
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x;
}
#define MAXN 2000100
int N,Q,id[MAXN];
char S[MAXN];
namespace ACMachine
{
struct TrieNode{int son[MAXN][],fail[MAXN],end[MAXN];}trie;
int sz=;
inline void Insert(int x)
{
int now=,len=strlen(S+);
for (int i=; i<=len; i++)
if (trie.son[now][S[i]-'a']) now=trie.son[now][S[i]-'a'];
else now=trie.son[now][S[i]-'a']=++sz,now=sz;
trie.end[now]=;
id[x]=now;
}
inline void Buildfail()
{
queue<int>q; q.push();
while (!q.empty())
{
int now=q.front(); q.pop();
for (int i=; i<; i++)
if (trie.son[now][i])
{
int fa=trie.fail[now];
while (fa && !trie.son[fa][i]) fa=trie.fail[fa];
trie.fail[trie.son[now][i]]=fa? trie.son[fa][i] : ;
q.push(trie.son[now][i]);
}
}
}
}
using namespace ACMachine;
namespace FailTree
{
struct EdgeNode{int next,to;}edge[MAXN<<];
int head[MAXN],cnt;
inline void AddEdge(int u,int v) {cnt++; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt;}
inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
inline void BuildTree() {for (int i=; i<=sz; i++) InsertEdge(trie.fail[i],i);}
}
using namespace FailTree;
namespace Divide
{
int size[MAXN],deep[MAXN],fa[MAXN],son[MAXN],pl[MAXN],dfn,pre[MAXN],top[MAXN],pr[MAXN];
inline void DFS_1(int now,int last)
{
size[now]=;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last)
{
deep[edge[i].to]=deep[now]+;
fa[edge[i].to]=now;
DFS_1(edge[i].to,now);
size[now]+=size[edge[i].to];
if (size[son[now]]<size[edge[i].to]) son[now]=edge[i].to;
}
}
inline void DFS_2(int now,int chain)
{
pl[now]=++dfn; pre[dfn]=now; top[now]=chain;
if (son[now]) DFS_2(son[now],chain);
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=fa[now] && edge[i].to!=son[now])
DFS_2(edge[i].to,edge[i].to);
pr[now]=dfn;
}
inline int LCA(int x,int y)
{
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
x=fa[top[x]];
}
return deep[x]<deep[y]? x:y;
}
}
using namespace Divide;
namespace BIT
{
int tree[MAXN];
inline int lowbit(int x) {return x&-x;}
inline void Modify(int p,int d) {for(int i=p; i<=sz; i+=lowbit(i)) tree[i]+=d;}
inline int Query(int p) {int re=; for (int i=p; i; i-=lowbit(i)) re+=tree[i]; return re;}
inline int Query(int l,int r) {return Query(r)-Query(l-);}
}
using namespace BIT;
int st[MAXN],tp,to;
inline bool cmp(int x,int y) {return pl[x]<pl[y];}
int main()
{
N=read();
for (int i=; i<=N; i++) scanf("%s",S+),ACMachine::Insert(i);
ACMachine::Buildfail();
FailTree::BuildTree();
DFS_1(,); DFS_2(,);
Q=read();
while (Q--)
{
int opt=read(),le; char str[MAXN];
switch (opt)
{
case :
scanf("%s",str+); le=strlen(str+); tp=to=;
for (int now=,i=; i<=le; i++)
{
while (now && !trie.son[now][str[i]-'a']) now=trie.fail[now];
now=trie.son[now][str[i]-'a'];
if (now!=) st[++tp]=now;
}
sort(st+,st+tp+,cmp);
st[to]=-; for (int i=; i<=tp; i++) if (st[to]!=st[i]) st[++to]=st[i];
for (int i=; i<=to; i++) Modify(pl[st[i]],);
for (int i=; i<=to; i++) Modify(pl[LCA(st[i-],st[i])],-);
break;
case : int x=read(); printf("%d\n",Query( pl[id[x]] , pr[id[x]] )); break;
}
}
return ;
}

想找个机会整理一下fail树的一些性质....

【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序的更多相关文章

  1. 【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序

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

  2. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Sta ...

  3. BZOJ.2434.[NOI2011]阿狸的打字机(AC自动机 树状数组 DFS序)

    题目链接 首先不需要存储每个字符串,可以将所有输入的字符依次存进Trie树,对于每个'P',记录该串结束的位置在哪,以及当前节点对应的是第几个串(当前串即根节点到当前节点):对于'B',只需向上跳一个 ...

  4. BZOJ 2780 Sevenk Love Oimaster (后缀自动机+树状数组+dfs序+离线)

    题目大意: 给你$n$个大串和$m$个询问,每次给出一个字符串$s$询问在多少个大串中出现过 好神的一道题 对$n$个大串建出广义$SAM$,建出$parent$树 把字符串$s$放到$SAM$里跑, ...

  5. luogu SP8093 后缀自动机+树状数组+dfs序

    这题解法很多,简单说几个: 1. 线段树合并,时间复杂度是 $O(nlog^2n)$ 的. 2. 暴力跳 $fail,$ 时间复杂度 $O(n\sqrt n),$ 比较暴力. 3. 建立后缀树后在 $ ...

  6. BZOJ 1103 [POI2007]大都市meg(树状数组+dfs序)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1103 [题目大意] 给出一棵树,每条边的经过代价为1,现在告诉你有些路不需要代价了, ...

  7. BZOJ 4765: 普通计算姬 [分块 树状数组 DFS序]

    传送门 题意: 一棵树,支持单点修改和询问以$[l,r]$为根的子树的权值和的和 只有我这种不会分块的沙茶不会做这道题吗? 说一点总结: 子树和当然上$dfs$序了,询问原序列一段区间所有子树和,对原 ...

  8. 【BZOJ-1103】大都市meg 树状数组 + DFS序

    1103: [POI2007]大都市meg Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2009  Solved: 1056[Submit][Sta ...

  9. POJ 3321 Apple Tree (树状数组+dfs序)

    题目链接:http://poj.org/problem?id=3321 给你n个点,n-1条边,1为根节点.给你m条操作,C操作是将x点变反(1变0,0变1),Q操作是询问x节点以及它子树的值之和.初 ...

随机推荐

  1. HttpClient相关

    HTTPClient的主页是http://jakarta.apache.org/commons/httpclient/,你可以在这里得到关于HttpClient更加详细的信息 HttpClient入门 ...

  2. javascript 类型转换。

    学校js感觉好漫长,断断续续,要坚持每天都能学到点,总结了下数据类型的转换. Javascript的变量是松散类型的,它可以存储Javascript支持的任何数据类型,其变量的类型可以在运行时被动态改 ...

  3. SQL Server附加数据库失败错误号:5120的解决办法

    附加数据库时出现附加数据库失败的错误,错误号是5120,已经两次遇到这种问题了.今天写一下解决办法. 有两个方法,很简单: 1.设置mdf文件所在文件夹的权限,在文件夹上右击——属性——安全,如图所示 ...

  4. java编码原理,java编码和解码问题

    java的编码方式原理 java的JVM的缺省编码方式由系统的“本地语言环境”设置确定,和操作系统的类型无关 . 在JAVA源文件-->JAVAC-->Class-->Java--& ...

  5. Squirrel: 通用SQL、NoSQL客户端

    安装 配置数据库 配置驱动 配置连接 如果你的工作中,需要使用到多个数据库,又不想在多种客户端之间切换来切换去.那么就需要找一款支持多数据库的客户端工具了.如果你要连接多个关系型数据库,你就可以使用N ...

  6. linux ssh远程免登陆

    一.备份: 操作之前先将/root/.ssh/下的known_hosts备份成known_hosts.bak

  7. 史上最全QC学习方案,值得收藏!

    Quality Center是一个基于Web的强大的测试管理工具,可以组织和管理应用程序测试流程的所有阶段,**制定测试需求.计划测试.执行测试和跟踪缺陷.此外,通过Quality Center还可以 ...

  8. 项目自动化建构工具gradle 入门3——生一个exe的helloWorld

    前两次呢,我们能够用一个外部的jar 来实现输出helloWorld.但问题是我每次都要用java -jar 来执行,这样我们自己玩还可以,让用户玩就不好了.所以我们生成一个exe给他们吧.这次我们仍 ...

  9. 给Eclipse提速的7个技巧

    这篇文章只是关注如何让Eclipse运行得更快.每个技巧都针对Windows.Linux和MacOS用户详细说明.在使用所有优化技巧之后,Eclipse应该能在10秒内启动,并且比以前运行得更流畅. ...

  10. github page+jekyll搭博客初体验

    div.oembedall-githubrepos { border: 1px solid #DDD; list-style-type: none; margin: 0 0 10px; padding ...