题目大意:

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遇到了困难,需要你的帮助。
 

最先想歪了,想把$T$里的串建自动机,最后失败了..

正解是对Alice的字符串建AC自动机,再建$Fail$树

那么对于操作1,每加入一个字符串,就把这个串放到AC自动机上跑

再把路径上的所有点记下来,新加入的字符串会对连接这些节点的树链上的所有点产生1点贡献

即求树链的并,用树状数组维护$dfs$序

先把这些节点按照$dfs$序排序,然后在树上打差分,树状数组维护前缀和,单点修改

每个节点都+1,$dfs$序中相邻节点的$lca$-1,最后在全局$lca$的父节点-1

询问就是子树查询

 #include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define NN 2001000
#define MM 1510
#define ll long long
#define dd double
#define uint unsigned int
#define mod 1000000007
#define idx(X) (X-'a')
#define eps (1e-9)
using namespace std; int n,m,cte;
int head[NN];
struct Edge{int to,nxt;}edge[NN];
void ae(int u,int v){
cte++;edge[cte].nxt=head[u];
head[u]=cte,edge[cte].to=v;
}
struct BIT{
int sum[NN*],tot;
void update(int x,int w){
for(int i=x;i<=tot;i+=(i&(-i)))
sum[i]+=w;}
int query(int x){
int ans=;
for(int i=x;i>;i-=(i&(-i)))
ans+=sum[i];
return ans;}
}b;
namespace AC{
int ch[NN][],fail[NN],tot,ed[NN],dep[NN];
void Build_Trie(char *str,int len,int id)
{
int x=;
for(int i=;i<=len;i++){
if(!ch[x][idx(str[i])])
ch[x][idx(str[i])]=++tot,
dep[tot]=dep[x]+;
x=ch[x][idx(str[i])];
}ed[id]=x;
}
void Build_Fail()
{
queue<int>q;
for(int i=;i<;i++)
if(ch[][i]) q.push(ch[][i]);
while(!q.empty())
{
int x=q.front();q.pop();
ae(fail[x],x);
for(int i=;i<;i++)
{
if(ch[x][i]){
fail[ch[x][i]]=ch[fail[x]][i];
q.push(ch[x][i]);
}else{
ch[x][i]=ch[fail[x]][i];
}
}
}
}
};
char str[NN];
namespace T{
int son[NN],sz[NN],tp[NN],fa[NN],dep[NN];
int st[NN],ed[NN],tot;
void dfs1(int u,int dad)
{
for(int j=head[u];j;j=edge[j].nxt){
int v=edge[j].to;
if(v==dad) continue;
fa[v]=u;dep[v]=dep[u]+;
dfs1(v,u);
son[u]=sz[v]>sz[son[u]]?v:son[u];
}sz[u]++;
}
void dfs2(int u)
{
st[u]=++tot;
if(son[u]) tp[son[u]]=tp[u],dfs2(son[u]);
for(int j=head[u];j;j=edge[j].nxt){
int v=edge[j].to;
if(v==fa[u]||v==son[u]) continue;
tp[v]=v,dfs2(v);
}ed[u]=++tot;
}
int LCA(int x,int y)
{
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
x=fa[tp[x]];
}return dep[x]<dep[y]?x:y;
}
int stk[NN],num;
int cmp(int x,int y){return st[x]<st[y];}
void update(char *str,int len)
{
int x=,y,ff,v;
for(int i=;i<=len;i++){
v=AC::ch[x][idx(str[i])];
if((!v)) break;
x=v;stk[++num]=x;
}
sort(stk+,stk+num+,cmp);
x=stk[];
if(num==){
b.update(st[x],);
b.update(st[fa[x]],-);
}else{
b.update(st[x],);
for(int i=;i<=num;i++)
{
y=stk[i];ff=LCA(x,y);
b.update(st[y],);
b.update(st[ff],-);
x=stk[i];
}ff=LCA(stk[],stk[num]);
b.update(st[fa[ff]],-);
}
while(num) stk[num--]=;
}
int query(int x)
{return b.query(ed[x])-b.query(st[x]-);}
void solve()
{
dep[]=;dfs1(,-);
tp[]=;dfs2();
scanf("%d",&m);
int fl,x;
b.tot=tot;
for(int i=;i<=m;i++)
{
scanf("%d",&fl);
if(fl==){
scanf("%s",str+);
int len=strlen(str+);
update(str,len);
}else{
scanf("%d",&x);
printf("%d\n",query(AC::ed[x]));
}
}
}
}; int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%s",str+);
int len=strlen(str+);
AC::Build_Trie(str,len,i);
}AC::Build_Fail();
T::solve();
return ;
}
 
 

BZOJ 3881 [COCI2015]Divljak (Trie图+Fail树+树链的并+树状数组维护dfs序)的更多相关文章

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

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

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

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

  3. BZOJ 3881 [Coci2015]Divljak(AC自动机+树状数组)

    建立AC自动机然后,加入一个串之后考虑这个串的贡献.我们把这个串扔到AC自动机里面跑.最后对经过每一个点到的这个点在fail树的根的路径上的点有1的贡献.求链的并,我们把这些点按DFS序排序,然后把每 ...

  4. BZOJ 3881: [Coci2015]Divljak

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

  5. bzoj 3881 [Coci2015]Divljak fail树+树链的并

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

  6. bzoj 3881 [Coci2015]Divljak——LCT维护parent树链并

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3881 对 S 建 SAM ,每个 T 会让 S 的 parent 树的链并答案+1:在 T ...

  7. bzoj 3881: [Coci2015]Divljak AC自动机

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3881 题解: 这道题我想出了三种做法,不过只有最后一种能过. 第一种: 首先我们把所有的 ...

  8. BZOJ 3881[COCI2015]Divljak (AC自动机+dfs序+lca+BIT)

    显然是用AC自动机 先构建好AC自动机,当B中插入新的串时就在trie上跑,对于当前点,首先这个点所代表的串一定出现过,然后这个点指向的fail也一定出现过.那么我们把每个点fail当作父亲,建一棵f ...

  9. (好题)树状数组+离散化+DFS序+离线/莫队 HDOJ 4358 Boring counting

    题目传送门 题意:给你一棵树,树上的每个节点都有树值,给m个查询,问以每个点u为根的子树下有多少种权值恰好出现k次. 分析:首先要对权值离散化,然后要将树形转换为线形,配上图:.然后按照右端点从小到大 ...

随机推荐

  1. @DateTimeFormat无效原因

    一般都是使用@DateTimeFormat把传给后台的时间字符串转成Date,使用@JsonFormat把后台传出的Date转成时间字符串,但是@DateTimeFormat只会在类似@Request ...

  2. Windows系统Python环境搭建

    Python下载 下载地址:https://www.python.org/downloads/ 选择需要下载的版本 以Python3.3.7版本为例,下载64位和32位都分别有三种方式,依次是压缩包, ...

  3. 再次理解JS的prototype,__proto__和constructor

    个人总结: 下面这篇文章很好的讲解了js原型,原型链,个人的总结是要记住这三个属性 prototype.__proto__和constructor 首先明确,js中一切都是对象object(A). ( ...

  4. Parse error: syntax error, unexpected '__data' (T_STRING), expecting ',' or ')'

    使用laravel时,建立view文件引入dafault文件时报错: Parse error: syntax error, unexpected '__data' (T_STRING), expect ...

  5. HDU 4535 吉哥系列故事——礼尚往来( 错排水题 )

    链接:传送门 思路:错排模板题,水题是非常浪费时间的. /*********************************************************************** ...

  6. AMD包下载及使用

    AMD下载 下载地址 选择837.zip下载即可,将837.zib考入相应的文件夹下,并解压缩 wget http://netlib.org/toms/837.zip unzip 837.zip cd ...

  7. html全屏显示

    JavaScript代码: function toggleFullScreen() { if (!document.fullscreenElement && // alternativ ...

  8. Numpy的使用规则

    之前安装的python版本是3.7 各种库都是自己一个一个下载安装的 很操心 各种缺功能 后来发现了anaconda 啊 真是一个好东西 简单来说 它就是一个涵盖大部分常用库的python包 一次安装 ...

  9. Vue - vue.js 常用指令

    Vue - vue.js 常用指令 目录: 一. vuejs模板语法之常用指令 1. 常用指令: v-html 2. 常用指令: v-text 3. 常用指令: v-for 4. 常用指令: v-if ...

  10. KMP算法题集

    模板 caioj 1177 KMP模板 #include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i & ...