Divljak

Alice 有 $n$ 个字符串 $ S_1,S_2,\cdots,S_n $ ,Bob有一个字符串集合 $T$ ,一开始集合是空的。

接下来会发生 $q$ 个操作,操作有两种形式:

“ $1~P$ ”,Bob 往自己的集合里添加了一个字符串 $P$ 。

“ $2~x$ ”,Alice 询问 Bob,集合 $T$ 中有多少个字符串包含串 $S_x$ 。

(我们称串 $A$ 包含串 $B$ ,当且仅当 $B$ 是 $A$ 的子串)

Bob 遇到了困难,需要你的帮助。


Sol

考虑S集建AC自动机。

每次把新加入的串扔进去匹配,所有匹配位置加1。

查询时就是子树和。

但是有重复算的情况。我们把所有要加的点按dfs序排序,然后把相邻两两的lca-1

这样就不重了,lca之上的点会+2-1

卡常差评

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define maxn 2000006
using namespace std;
int num,n,tr[maxn][],fail[maxn],p[maxn],tot,cnt;
int head[maxn],f[maxn],deep[maxn],dfn[maxn],sc;
int son[maxn],sz[maxn],top[maxn],tree[maxn],a[maxn];
struct node{
int v,nex;
}e[maxn*];
char s[maxn];
void ins(int id){
int len=strlen(s),k=;
for(int i=;i<len;i++){
if(!tr[k][s[i]-'a'])tr[k][s[i]-'a']=++n;
k=tr[k][s[i]-'a'];
}
p[id]=k;
}
void build(){
queue<int>q;
for(int i=;i<;i++)if(tr[][i])q.push(tr[][i]);
while(!q.empty()){
int k=q.front();q.pop();
for(int i=;i<;i++){
if(tr[k][i]){
fail[tr[k][i]]=tr[fail[k]][i];
q.push(tr[k][i]);
}
else tr[k][i]=tr[fail[k]][i];
}
}
}
void lj(int t1,int t2){
e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs1(int k,int fa){
f[k]=fa;deep[k]=deep[fa]+;
sz[k]=;int gp=;
for(int i=head[k];i;i=e[i].nex){
dfs1(e[i].v,k);
sz[k]+=sz[e[i].v];
if(sz[e[i].v]>sz[gp] || !gp)gp=e[i].v;
}
son[k]=gp;
}
void dfs2(int k){
dfn[k]=++sc;
if(son[k])top[son[k]]=top[k],dfs2(son[k]);
for(int i=head[k];i;i=e[i].nex)
if(e[i].v!=son[k])top[e[i].v]=e[i].v,dfs2(e[i].v);
}
void add(int i,int v){
for(;i<=n;i+=i&-i)tree[i]+=v;
}
int ask(int i){
int sum=;for(;i;i-=i&-i)sum+=tree[i];
return sum;
}
bool cmp(int a,int b){
return dfn[a]<dfn[b];
}
int lca(int a,int b){
int t1=top[a],t2=top[b];
while(t1!=t2){
if(deep[t1]<deep[t2])swap(t1,t2);
a=f[t1],t1=top[a];
}
return deep[a]>deep[b]?b:a;
}
void work(){
int tp=;
int k=;int len=strlen(s);
for(int i=;i<len;i++){
k=tr[k][s[i]-'a'];a[++tp]=k;
//add(dfn[k],1);
}
sort(a+,a+tp+,cmp);
add(dfn[a[]],);
for(int i=;i<=tp;i++)add(dfn[a[i]],),add(dfn[lca(a[i],a[i-])],-);
}
int main()
{
scanf("%d",&num);
for(int i=;i<=num;i++){
scanf(" %s",s);ins(i);
}
build(); for(int i=;i<=n;i++)lj(fail[i],i);
n++;dfs1(,n);dfs2();
int q;scanf("%d",&q);
for(int i=,op;i<=q;i++){
scanf("%d",&op);
if(op==){
scanf("%s",s);work();
}
else {
int t;scanf("%d",&t);t=p[t];
printf("%d\n",ask(dfn[t]+sz[t]-)-ask(dfn[t]-));
}
}
return ;
}

Divljak的更多相关文章

  1. 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序

    3881: [Coci2015]Divljak Time Limit: 20 Sec  Memory Limit: 768 MBSubmit: 508  Solved: 158[Submit][Sta ...

  2. 字符串(AC自动机):COCI 2015 round 5 divljak

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAy0AAANaCAIAAAALVTQoAAAgAElEQVR4nOy9X2hbx773PXfrQgQjDq

  3. BZOJ 3881: [Coci2015]Divljak [AC自动机 树链的并]

    3881: [Coci2015]Divljak 题意:添加新文本串,询问某个模式串在多少种文本串里出现过 模式串建AC自动机,考虑添加一个文本串,走到的节点记录下来求树链的并 方法是按dfs序排序去重 ...

  4. BZOJ 3881: [Coci2015]Divljak

    3881: [Coci2015]Divljak Time Limit: 20 Sec  Memory Limit: 768 MBSubmit: 553  Solved: 176[Submit][Sta ...

  5. 【BZOJ3881】[Coci2015]Divljak fail树+树链的并

    [BZOJ3881][Coci2015]Divljak Description Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操 ...

  6. BZOJ3881 : [Coci2015]Divljak

    对Alice的所有串构造AC自动机,并建出Fail树 每当Bob添加一个串时,在AC自动机上走,每走到一个点,就把它到根路径上所有点的答案+1 需要注意的是每次操作,相同的点只能被加一次 所以在需要操 ...

  7. [Coci2015]Divljak

    题目描述  Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  8. BZOJ3881 Divljak

    解:对被包含的那些串建AC自动机. 每次加一个串,就在AC自动机上面跑,可知能够跑到一些节点. 这些节点都是一些前缀的形式,我们跳fail树就是跳后缀,这样就能够得到所有能匹配的子串. 我们分别对AC ...

  9. BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

随机推荐

  1. PHP 面向对象编程笔记 (麦子 php 第二阶段)

    类是把具有相似特性的对象归纳到一个类中,类就是一组相同属性和行为的对象的集合.类和对象的关系:类是相似对象的描述,先有类,再有对象.类是对象的抽象,对象是类的实例.通过class关键字创建类,成员属性 ...

  2. html5 获取和设置data-*属性值的四种方法讲解

    1.获取id的对象 2.需要获取的就是data-id 和 dtat-vice-id的值 一:getAttribute()方法 const getId = document.getElementById ...

  3. ExceL按记录导出Txt 工具

    根据客户要求,开发此工具,每一条记录改出一个Txt文本,文本名取其中一字段数据

  4. C# 设置程序最小化到任务栏右下角,鼠标左键单击还原,右键提示关闭程序

    首先设置程序最小化到任务栏右下角 先给窗口添加一个notifyIcon控件 为notifyIcon控件设置ICO图标(不设置图标将无法在任务栏显示) 给notifyIcon控件添加点击事件 然后是最小 ...

  5. (数据科学学习手札16)K-modes聚类法的简介&Python与R的实现

    我们之前经常提起的K-means算法虽然比较经典,但其有不少的局限,为了改变K-means对异常值的敏感情况,我们介绍了K-medoids算法,而为了解决K-means只能处理数值型数据的情况,本篇便 ...

  6. python2.7练习小例子(二十)

        20):题目:猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,又多吃了一个.以后每天早上都吃了前一天剩下的一半零一个.到第10天早上 ...

  7. JavaScript---设计模式简介

    概念 设计模式(Design pattern)是一套被反复使用.思想成熟.经过分类和无数次实战设计经验的总结的.使用设计模式是为了让系统代码可重用.可扩展.可解耦.更容易被人理解且能保证代码的可靠性. ...

  8. javascript-es6学习笔记

    es6技术培训文档 第一阶段:1.let与const用法2.变量的解构赋值3.字符串的扩展4.正则的扩展5.数组的扩展6.函数的扩展7.对象的扩展8.Symbol9.Set和Map数据结构 第二阶段: ...

  9. php用GD库给图片添加水印

    php用GD库给图片添加文字水印,整个代码比较简单,DEMO如下: <?php /*打开图片*/ //1.配置图片路径 $src = "aeroplane.jpg"; //2 ...

  10. Eclipse+APKTool动态调试APK

    1. 所需工具 Eclipse. Apktool v2.0.6. 安卓SDK工具. 2. 重编译APK apktool d -d -o test test.apk 此时当前test目录下就是apkto ...