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. Java面试题整理二(侧重SSH框架)

    1.持久化对象的状态都有哪些? 答:瞬时对象(Transient Objects):使用new 操作符初始化的对象不是立刻就持久的.它们的状态是瞬时的,也就是说它们没有任何跟数据库表相关联的行为,只要 ...

  2. UITabBarController 基本定制

    UITabBarController 定制 特点 用法 1.准备好你的tabBar图片及其他图片(哈哈哈!!!!),我的图片都放在了Assets.xcassets中. 2.导入本工程中的Categro ...

  3. NFR

    你NFR了吗? NFR,即非功能性需求 (Non -Functional Requirements) ,即系统能够完成所期望的工作的性能与质量.具体包括如下内容: – 效率: 软件实现其功能所需要的计 ...

  4. SQL*Plus环境下创建PLUSTRACE角色

    普通用户在SQL*Plus中开启AUTOTRACE报告时,遇到SP2-0618: Cannot find the Session Identifier. Check PLUSTRACE role is ...

  5. 2.sort 排序命令讲解

    sort命令  sort:文本排序,仅仅是对显示文件的排序,而不影响源文件的顺序,是根据ASSII码     的字符升序来排列的.        -n:安装数值大小从小到大排列 ,默认是升序.     ...

  6. docker 基础使用

    搜索某个镜像: docker  search  busybox 拉取: docker  pull  busybox 查看: docker  images 启动并运行: docker run -it b ...

  7. 如何打开、关闭IIS服务器

    问题描述:如题. 使用工具:腾讯云Windows Server 2012 R2 数据中心版 64位中文版. 操作步骤: 1.服务器管理器->IIS

  8. ACCELEROMETER

    顾名思义,是加速感应器.有2种应用吧:1,电脑保护,例如当笔记本掉落时,可以被自动检测到,此时会自动关闭硬盘操作以保护数据不在强烈冲击时丢失.

  9. Keepalived使用梳理

    keepalived介绍keepalived观察其名可知,保持存活,在网络里面就是保持在线了,也就是所谓的高可用或热备,它集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防 ...

  10. mongodb集群安装及到现在遇到的一些问题

    集群搭建 只有3台服务器,开始搭建mongodb集群里主要参照的是http://www.lanceyan.com/tech/arch/mongodb_shard1.html,端口的设置也是mongos ...