BZOJ3881 Coci2015 Divljak fail树+差分
题目大意,给出两个字符串集合S和T,向T中添加字符串,查询S_i在T中有几个字符串出现过。一看这种多字符串匹配问题,我们联想到了AC自动机,做法就是,对于S集合我们建立一个AC自动机,建出fail树,fail树有一个很好的性质就是,对于一个节点x,它所对应的字符串是它子树中所有节点对应的字符串的后缀。我们考虑如果S_x在P_x 中出现过,他肯定是P_x某一个前缀的后缀,所以我们把P_x在AC自动机上跑,跑到每一个节点我们更新一下他所在的fail树,统计答案的时候只需统计子树的大小就行了。但是这样会有一点小问题,就是会统计重复,如果对于每一个前缀我们都更新一下它到跟的路径和,这样会重复,因为S_x可能会在P_x中出现多次。实际上我们求的是一个点的子树所有链的并集,解决方案很巧妙,利用树上差分,我们按照dfs序排好顺序,然后相邻的两个节点的lca处-1就行了,这样就不会统计重复,利用树状数组维护一下dfs序即可。(有一点需要注意,在trie树上我们一共有tot个节点,那么对于fail树我们有tot+1个节点,树状数组大小注意一下,一开始错在了这里)——by VANE
#include<bits/stdc++.h>
using namespace std;
const int N=;
char s[N];
vector<int> g[N];
int son[N][],fail[N],L[N],R[N],a[N];
int sum[N],pos[N],id[N],dep[N];
int mn[N*][],LOG[N*];
int tot,n,dfn,cnt;
int cmp(int x,int y)
{
return L[x]<L[y];
}
void dfs(int u)
{
L[u]=++dfn;
mn[pos[u]=++cnt][]=u;
for(int i=;i<g[u].size();++i)
{
int v=g[u][i];
dep[v]=dep[u]+;
dfs(v);
mn[++cnt][]=u;
}
R[u]=dfn;
}
void insert(int x)
{
int l=strlen(s+);
int p=;
for(int j=;j<=l;++j)
{
if(!son[p][s[j]-'a']) son[p][s[j]-'a']=++tot;
p=son[p][s[j]-'a'];
}
id[x]=p;
}
void getfail()
{
queue<int> q;
for(int i=;i<;++i)
if(son[][i]) q.push(son[][i]);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=;i<;++i)
if(son[u][i])
fail[son[u][i]]=son[fail[u]][i],q.push(son[u][i]);
else son[u][i]=son[fail[u]][i];
}
}
int query(int x)
{
int res=;
for(;x;x-=x&-x)
res+=sum[x];
return res;
}
int lca(int x,int y)
{
if(pos[x]<pos[y]) swap(x,y);
int len=pos[x]-pos[y]+;
len=LOG[len];
return min(mn[pos[y]][len],mn[pos[x]-(<<len)+][len],cmp);
}
void add(int x,int w)
{
for(;x<=tot+;x+=x&-x)
sum[x]+=w;
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;++i)
{
scanf("%s",s+);
insert(i);
}
getfail();
for(int i=;i<=tot;++i) g[fail[i]].push_back(i);
dfs();
for(int k=;(<<k)<=cnt;++k) LOG[<<k]=k;
for(int i=;i<=cnt;++i)
if(!LOG[i]) LOG[i]=LOG[i-];
for(int k=;k<=LOG[cnt];++k)
for(int i=;i+(<<k)-<=cnt;++i)
mn[i][k]=min(mn[i][k-],mn[i+(<<k-)][k-],cmp);
int q;
scanf("%d",&q);
while(q--)
{
int opt;scanf("%d",&opt);
if(opt==)
{
scanf("%s",s+);
int l=strlen(s+);
int p=;
for(int i=;i<=l;++i)
a[i]=p=son[p][s[i]-'a'];
sort(a+,a++l,cmp);
for(int i=;i<=l;++i)
add(L[a[i]],);
for(int i=;i<l;++i)
{
int x=lca(a[i],a[i+]);
add(L[x],-);
}
}
else
{
int x;
scanf("%d",&x);
printf("%d\n",query(R[id[x]])-query(L[id[x]]-));
}
}
}
BZOJ3881 Coci2015 Divljak fail树+差分的更多相关文章
- 【BZOJ3881】[Coci2015]Divljak fail树+树链的并
[BZOJ3881][Coci2015]Divljak Description Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操 ...
- bzoj 3881 [Coci2015]Divljak fail树+树链的并
题目大意 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: "1 P",Bob往自己的集合里添 ...
- BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- BZOJ3881 : [Coci2015]Divljak
对Alice的所有串构造AC自动机,并建出Fail树 每当Bob添加一个串时,在AC自动机上走,每走到一个点,就把它到根路径上所有点的答案+1 需要注意的是每次操作,相同的点只能被加一次 所以在需要操 ...
- 【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 AC自动机+树链的并+DFS序+树状数组
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- BZOJ 3881 [COCI2015]Divljak (Trie图+Fail树+树链的并+树状数组维护dfs序)
题目大意: Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- BZOJ 3881: [Coci2015]Divljak [AC自动机 树链的并]
3881: [Coci2015]Divljak 题意:添加新文本串,询问某个模式串在多少种文本串里出现过 模式串建AC自动机,考虑添加一个文本串,走到的节点记录下来求树链的并 方法是按dfs序排序去重 ...
- BZOJ-3881:Divljak (AC自动机+DFS序+树链求并+树状数组)
Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. “2 x” ...
随机推荐
- FastDFS图片服务器java后台的简单调用
工具类: package com.liveyc.common.fdfs; import org.apache.commons.io.FilenameUtils; import org.csource. ...
- 【洛谷 P4134】 [BJOI2012]连连看(费用流)
题目链接 首先是可以\(O(n^2)\)枚举出所有符合要求的点对的,然后考虑建图. 还是拆点把每个点拆成入点和出点,源点连入点,出点连汇点,流量都是1,费用都是0. 然后对于没对符合要求的\((x,y ...
- Metasploit 一些重要模块使用介绍
本文是"T00LS Metasploit(第一季)"的文档版,是个人在观看视频动手操作的一个记录,仅供学习.文中会介绍Metasploit的一些基本使用:端口扫描.smb扫描.服务 ...
- webgote的例子(5)Sql注入(Blog)
SQL Injection - Stored (Blog) (本章内容):留言板的注入 看到这个页面先看以下这个页面是做什么的.进行正常的写入发现我每写一句话,其内容都会写到下面的entry里面 在尝 ...
- webconfig的配置解析
<?xml version="1.0"?> <!--注意: 除了手动编辑此文件以外,您还可以使用 Web 管理工具来配置应用程序的设置.可以使用 Visual S ...
- Sklearn-GridSearchCV网格搜索
GridSearchCV,它存在的意义就是自动调参,只要把参数输进去,就能给出最优化的结果和参数.但是这个方法适合于小数据集,一旦数据的量级上去了,很难得出结果.这个时候就是需要动脑筋了.数据量比较大 ...
- jsonpath for js
/** * @license * JSONPath 0.8.0 - XPath for JSON * * Copyright (c) 2007 Stefan Goessner (goessner.ne ...
- html 简单学习
通过记事本,依照以下四步来创建您的第一张网页. 步骤一:启动记事本 如何启动记事本: 开始 所有程序 附件 记事本 步骤二:用记事本来编辑 HTML 在记事本 ...
- mongodb与mysql传统的关系数据库区别
转自:易百教程 MongoDB中的数据具有灵活的模式.文档在同一集合,但它们不需要具有相同的字段或结构集合,集合文档中的公共字段可以包含不同类型的数据. MongoDB中的数据具有灵活的模式.与SQL ...
- 【转】doxygen+graphviz生成工程中的类继承树及函数调用图
转自----hequn8128 在阅读代码量比较多的项目时,类的继承树和函数调用图能够直观地向我们显示类之间或者函数之间的各种关系,方便我们了解程序的整体框架,很多时候可以起到事半功倍的作用.这里尝试 ...