BZOJ-3881:Divljak (AC自动机+DFS序+树链求并+树状数组)
Input
Output
Sample Input
3
a
bc
abc
5
1 abca
2 1
1 bca
2 2
2 3
Sample Output
1
2
1
Hint
之前就看过此题,但是不会树链求并,就搁着了。现在回来看还是可以做的。
Alice在字符串集合为S,Bob的字符串集合为T。先对Alice的集合建立AC自动机,得到Fail树。对于T每次新加的字符串Str,Str在自动机上跑。能跑到的所有 位置,在Fail树上对应的位置到根的所有点都要加1,重复的不重复加,就涉及到去重,即用树链求并。
把跑到是所有位置对应的Fail树位置按DFS序排序,每一个位置+1,相邻的LCA位置处-1。那么求T中有几个串含有某Si时,即是求Si在Fail树上的子树值之和。这里倍增求LCA会超时。
这个人的代码风格和我一模一样哎(但是他的AC自动机写丑了)!!!因为是权限题,自己写一遍怕错了没法知晓,就假设我写了,去找个差不多的题写写,233。
#include<bits/stdc++.h>
using namespace std; #define N 2002010
int ch[N][],fail[N],ins[N],cnt;
char s[N]; int head[N],next[N],end[N];
inline void addedge(int a,int b){
static int q=;end[q]=b,next[q]=head[a],head[a]=q++;
} int in[N],out[N],dep[N],tclock;
void dfs(int x){
in[x]=++tclock;
for(int j=head[x];j;j=next[j])
dep[end[j]]=dep[x]+,dfs(end[j]);
out[x]=tclock;
} namespace Lca_system{
int Seq[N<<],a[],M,ins[N],cnt;
inline void build_dfs(int x){
ins[x]=++cnt;
Seq[cnt]=x;
for(int j=head[x];j;j=next[j]){
build_dfs(end[j]);
Seq[++cnt]=x;
}
}
inline int Min(int x,int y){
if(x==-||y==-)return x==-?y:x;
return dep[x]<dep[y]?x:y;
}
inline void init(){
build_dfs();
for(M=;M<cnt+;M<<=);
memset(a,-,sizeof a);
for(int i=;i<=cnt;++i)a[M+i]=Seq[i];
for(int i=M-;i>=;--i)a[i]=Min(a[*i],a[*i+]);
}
inline int ask(int tl,int tr){
int re=-;
for(tl+=M-,tr+=M+;tl^tr^;tl>>=,tr>>=){
if(~tl&)re=Min(re,a[tl^]);
if(tr&)re=Min(re,a[tr^]);
}
return re;
}
inline int lca(int x,int y){
x=ins[x],y=ins[y];
if(x>y)swap(x,y);
return ask(x,y);
}
} int seq[N],num; int A[N];
inline void modify(int x,int c){
for(;x<=cnt+;x+=x&-x)A[x]+=c;
}
inline int ask(int x){
int re=;for(;x;x-=x&-x)re+=A[x];return re;
} inline bool cmp(const int&x,const int&y){return in[x]<in[y];} inline int git(){
int c,re;
while(!isdigit(c=getchar()));
re=c-'';
while(isdigit(c=getchar()))re=(re<<)+(re<<)+c-'';
return re;
}
char buf[*],*o=buf;
inline void print(int x){
static int s[];int top=;
if(!x)*o++=;else{for(;x;x/=)s[++top]=x%;for(int i=top;i>=;--i)*o++=+s[i];}
*o++='\n';
}
int main(){
int n=git();
register int i,j; int len,p;
for(i=;i<=n;++i){
scanf("%s",s);
len=strlen(s),p=;
for(j=;j<len;++j){
if(!ch[p][s[j]-'a'])ch[p][s[j]-'a']=++cnt;
p=ch[p][s[j]-'a'];
}
ins[i]=p;
} queue<int>q;
for(i=;i<;++i) if(ch[][i]) q.push(ch[][i]);
int u,v,r;
while(!q.empty()){
u=q.front(),q.pop();
for(i=;i<;++i)if((v=ch[u][i])){
q.push(v);
for(r=fail[u];r&&!ch[r][i];r=fail[r]);
fail[v]=ch[r][i];
}
} for(i=;i<=cnt;++i) addedge(fail[i],i);
dep[]=,dfs();
Lca_system::init(); int Q=git(); int qte,x;
while(Q--){
qte=git();
if(qte==){
scanf("%s",s);
len=strlen(s),p=,num=;
for(i=;i<len;++i){
while(p&&!ch[p][s[i]-'a'])p=fail[p];
p=ch[p][s[i]-'a'];
if(p) seq[++num]=p;
}
sort(seq+,seq+num+,cmp);
for(i=;i<=num;++i)modify(in[seq[i]],);
for(i=;i<num;++i)modify(in[Lca_system::lca(seq[i],seq[i+])],-);
}
else{
x=git();
print(ask(out[ins[x]])-ask(in[ins[x]]-));
}
} fwrite(buf,,o-buf,stdout);
return ;
}
BZOJ-3881:Divljak (AC自动机+DFS序+树链求并+树状数组)的更多相关文章
- BZOJ 3881[COCI2015]Divljak (AC自动机+dfs序+lca+BIT)
显然是用AC自动机 先构建好AC自动机,当B中插入新的串时就在trie上跑,对于当前点,首先这个点所代表的串一定出现过,然后这个点指向的fail也一定出现过.那么我们把每个点fail当作父亲,建一棵f ...
- BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )
一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...
- BZOJ2434[Noi2011]阿狸的打字机——AC自动机+dfs序+树状数组
题目描述 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小 ...
- BZOJ 2434 阿狸的打字机(ac自动机+dfs序+树状数组)
题意 给你一些串,还有一些询问 问你第x个串在第y个串中出现了多少次 思路 对这些串建ac自动机 根据fail树的性质:若x节点是trie中root到t任意一个节点的fail树的祖先,那么x一定是y的 ...
- BZOJ_2434_[NOI2011]_阿狸的打字机_(AC自动机+dfs序+树状数组)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=2434 给出\(n\)个字符串,\(m\)个询问,对于第\(i\)个询问,求第\(x_i\)个字 ...
- 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
[BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...
- BZOJ2434: [NOI2011]阿狸的打字机(AC自动机+dfs序+树状数组)
[NOI2011]阿狸的打字机 题目链接:https://www.luogu.org/problemnew/show/P2414 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. ...
- [NOI2011][bzoj2434] 阿狸的打字机 [AC自动机+dfs序+fail树+树状数组]
题面 传送门 正文 最暴力的 最暴力的方法:把所有询问代表的字符串跑一遍kmp然后输出 稍微优化一下:把所有询问保存起来,把模板串相同的合并,求出next然后匹配 但是这两种方法本质没有区别,都是暴力 ...
- CodeForces 547E:Mike and Friends(AC自动机+DFS序+主席树)
What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercas ...
随机推荐
- Html5 播放Hls格式视频
二群号为766718184 ,博主提供Ffmpeg.GB28181视频教程 播放地址: http://www.iqiyi.com/u/1426749687 移动端Html5支持Hls格式视频播放,创 ...
- 修改Oracle SGA,以提高oracle性能
在正常情况下,查询非常慢. 1.检查SGA大小,以DBA身份连接到oracle数据库,输入show sga. 2.如果SGA过小,请修改其大小 修改SGA必须保持的原则 1).sga_target不能 ...
- HBase——完全分布
实际上,在真实环境中你需要使用完全分布配置完整测试HBase.在一个分布式配置中,集群有多个节点,每个节点运行一个或多个HBase守护进程.其中包括主Master和备份Master实例,多个Zooke ...
- sqlserver中的时间比较
例子: select count(*) from table where DATEDIFF ([second], '2004-09-18 00:00:18', '2004-09-18 00:00:19 ...
- wifi认证Portal开发系列(二):FreeRadius的安装和测试、关联Mysql
注:本次安装是基于FreeRadius 3版本进行安装配置的,在配置Mysql的过程中,与2版本有些不同.操作系统是CentOS 7 一.准备工作 工具的安装 #安装rz.sz命令用于文件上传 yum ...
- Linux kernel manpages
https://www.linuxquestions.org/questions/linux-newbie-8/man-pages-for-kernel-functions-758389/ 在Linu ...
- sealed,new,virtual,abstract与override关键字的区别?
1. sealed——“断子绝孙” 密封类不能被继承.密封方法可以重写基类中的方法,但其本身不能在任何派生类中进一步重写.当应用于方法或属性时,sealed修饰符必须始终与override一起使用. ...
- android利用apkplug框架实现主应用与插件通讯(传递随意对象)实现UI替换
时光匆匆,乍一看已半年过去了,经过这半年的埋头苦干今天最终有满血复活了. 利用apkplug框架实现动态替换宿主Activity中的UI元素.以达到不用更新应用就能够更换UI样式的目的. 先看效果图: ...
- 精彩回顾 HUAWEI HiAI 亮相华为北研所
从普通照片变成艺术品,仅需3秒: 从随手拍下的讲解胶片到生成规整清晰的ppt,只要瞬间…… 5月25日在华为北京研究所举办的HUAWEI HiAI技术合作交流会上,伴随着一声声惊叹,数款接入HUA ...
- Redis单台的安装部署及集群部署
Redis是一种高级key-value数据库.它跟memcached类似,不过数据可以持久化,而且支持的数据类型很丰富.有字符串,链表,集 合和有序集合.支持在服务器端计算集合的并,交和补集(diff ...