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. js url.slice(star,end) url.lastIndexOf('/') + 1, -4

    var url = '"http://60.195.252.25:15518/20151228/XXSX/作三角形的高.mp4")' document.title = url.sl ...

  2. querySelector系列方法相比 getElementsBy 系列方法有什么区别?

    querySelector 和  querySelectorAll 相比下面这些方法有什么区别? getElementsByTagName getElementsByClassName getElem ...

  3. 理解jQuery对象$.html

    前面的话 如果要比喻jQuery和原生javascript的关系,我个人认为是自动档和手动档汽车的区别.使用原生javascript,可以知道离合器以及档位的作用:而使用jQuery,则把离合器和手动 ...

  4. ios UIWebView自定义Alert风格的弹框

    之前开发过一个App,因为公司之前写好了网页版的内容和安卓版本的App,我进去后老板要求我ios直接用网页的内容,而不需要自己再搭建框架.我一听,偷笑了,这不就是一个UIWebView吗?简单! 但是 ...

  5. TiQuery

    TiQuery 是一个基于JQuery 的在Titanium上使用的 javascript 库 TiQuery 为TI 提供了很快捷的方法: // Utilities $.info('My messa ...

  6. iOS NSNotificationCenter详解

    通知中心的特点: 1:同步执行 2: 一对多发送消息 3: 降低程序耦合度 通知中心是单例,目的就是从任意一个发送消息到任意一个接收者,是同步执行的. 那么什么是同步呢? 用网上经典的说法,就是我叫朋 ...

  7. 基于IIS构建Pyathon Web服务

    本文简单叙述了在Windows下,如何利用IIS构建Python Web服务. 其主要步骤如下: 1.在IIS下构建一个站点,如图: 2.配置Python文件的处理程序,如图: 3.最后,在对应站点根 ...

  8. SVM一点心得体会

    支持向量机的学习说是刚刚开始,又不合理,只能说隔了很长的时间再看,终于在分类这块的层面上有了新的认识. 总的来说,支持向量机分为线性支持向量机和非线性支持向量机,线性支持向量机又可以分为硬间隔最大化线 ...

  9. url中的特殊符号含义

    1. # 10年9月,twitter改版.一个显著变化,就是URL加入了"#!"符号.比如,改版前的用户主页网址为http://twitter.com/username改版后,就变 ...

  10. C#中ToString()格式详解

    以下内容均摘自博客园,仅供资料查询. ToString格式化 在很多对象显示为字符串的时候都会使用到ToString中的格式化,由于以前没怎么注意到这个问题,想总结一下各个基础结构对象的格式化,以便后 ...