题目描述 

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遇到了困难,需要你的帮助。
题解
多串匹配问题,可以想到用AC自动机维护。
对于这种询问,每个串至多贡献一次的问题。
先是把每个T串在AC自动机上跑一遍,获得了一个点集,那么这些点在fail树上到根的路径上的所有点都会被贡献一次。
相当于这些链的并都被贡献了。
那我们的任务就是求链并。
一种方法是将所有点排一个序,然后对每个点到根的路径上加1,相邻两个点的LCA处-1。
链加不太好写,可以转化成统计子树和的形式,用BIT维护。
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define N 2000002
using namespace std;
typedef long long ll;
queue<int>q;
int tot,ch[N][],head[N],f[N],zh[N],topp,n,tr[N],tag[N],size[N],deep[N],fa[N],son[N],top[N],dfn[N],dfnn,tott,fan[N];
char s[N];
inline ll rd(){
ll x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
struct edge{int n,to;}e[N];
inline void add(int u,int v){
e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
inline void get_fail(){
for(int i=;i<;++i)if(ch[][i]){q.push(ch[][i]),add(,ch[][i]);}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=;i<;++i){;
if(ch[u][i])f[ch[u][i]]=ch[f[u]][i],add(f[ch[u][i]],ch[u][i]),q.push(ch[u][i]);
else ch[u][i]=ch[f[u]][i];
}
}
}
inline void upd(int x,int y){while(x<=dfnn)tr[x]+=y,x+=x&-x;}
inline int query(int x){int ans=;while(x)ans+=tr[x],x-=x&-x;return ans;}
inline void ins(int id){
int len=strlen(s);int now=;
for(int i=;i<len;++i){
if(!ch[now][s[i]-'a'])ch[now][s[i]-'a']=++tott;
now=ch[now][s[i]-'a'];
}
tag[id]=now;
}
void dfs(int u){
size[u]=;//cout<<u<<" ";
for(int i=head[u];i;i=e[i].n){
int v=e[i].to;deep[v]=deep[u]+;fa[v]=u;
dfs(v);
size[u]+=size[v];
if(size[v]>size[son[u]]||!son[u])son[u]=v;
}
}
void dfs2(int u){
if(!top[u])top[u]=u;dfn[u]=++dfnn;fan[dfnn]=u;
if(son[u])top[son[u]]=top[u],dfs2(son[u]);
for(int i=head[u];i;i=e[i].n){
int v=e[i].to;
if(v!=son[u])dfs2(v);
}
}
int getlca(int u,int v){
while(top[u]!=top[v]){
if(deep[top[u]]<deep[top[v]])swap(u,v);
u=fa[top[u]];
}
return min(dfn[u],dfn[v]);
}
int main(){
n=rd();
for(int i=;i<=n;++i){scanf("%s",s);ins(i);}
get_fail();
dfs();dfs2();
int q=rd();
while(q--){
int opt=rd();
if(opt==){
scanf("%s",s);int len=strlen(s),now=;topp=;
for(int i=;i<len;++i){
now=ch[now][s[i]-'a'];
zh[++topp]=dfn[now];
}
sort(zh+,zh+topp+);
for(int i=;i<=topp;++i){
upd(zh[i],);
if(i!=)upd(getlca(fan[zh[i-]],fan[zh[i]]),-);
}
}
else{
int x=tag[rd()];
printf("%d\n",query(dfn[x]+size[x]-)-query(dfn[x]-));
}
}
return ;
}

[Coci2015]Divljak的更多相关文章

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

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

  2. BZOJ 3881: [Coci2015]Divljak

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

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

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

  4. BZOJ3881 : [Coci2015]Divljak

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

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

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

  6. 【bzoj3881】[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组

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

  7. BZOJ3881 Coci2015 Divljak fail树+差分

    题目大意,给出两个字符串集合S和T,向T中添加字符串,查询S_i在T中有几个字符串出现过.一看这种多字符串匹配问题,我们联想到了AC自动机,做法就是,对于S集合我们建立一个AC自动机,建出fail树, ...

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

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

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

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

随机推荐

  1. BGP:所有邻居都启动了BGP,则无须建立首尾逻辑邻居,否则就需要首尾建立逻辑邻居。

    配置说明:都通过loopback 口作为bgp 连接口,并且要配置ebgp多跳,同时配置loopback口的静态路由. 以AR2为例: 第一种场景:所有直接相连的邻居都启动了BGP,则路由可以随意扩散 ...

  2. BGP:我们不生产路由,而是路由的搬运工

    1.BGP协议自身不能生产路由,它主要通过配置来将本地路由进行发布或者引入其他路由协议产生的路由. 有两种方法, 方法一.在BGP视图下,通过network命令将本地路由发布到BGP路由表中, 通过本 ...

  3. arcgis for js开发之路径分析

    arcgis for js开发之路径分析 //方法封装 function routeplan(x1, x2, y1, y2, barrierPathArray, isDraw, callback) { ...

  4. ADOConnection断线重连

    问题: ADOConnection断线重连问题描述: 使用ADOConnection连接oracle数据库,开始正常,当网络断开时数据库连接失败(此时查询ADOConnection.connected ...

  5. 单台MongoDB实例开启Oplog

    背景 随着数据的积累,MongoDB中的数据量越来越大,数据分析团队从数据库中抽取变化数据(假如依据栏位createdatetime,transdatetime),越来越困难.我们知道MongoDB的 ...

  6. 如何利用MongoDB打造TOP榜小程序

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯云数据库 TencentDB发表于云+社区专栏 今天我分享的主题内容大概是两部分,最主要的还是小游戏和小程序,第一部分就是跟大家分 ...

  7. centos7下git版本升级及gitlab安装

    centos系统自带的git版本过低,当使用git拉取.推送.克隆的时候可能会报错,常见的错误: error: The requested URL returned error: 401 Unauth ...

  8. 通过BulkLoad快速将海量数据导入到Hbase

    在第一次建立Hbase表的时候,我们可能需要往里面一次性导入大量的初始化数据.我们很自然地想到将数据一条条插入到Hbase中,或者通过MR方式等. 但是这些方式不是慢就是在导入的过程的占用Region ...

  9. 【spring源码分析】准备工作

    前言:之前写过两篇基于xml形式的IOC容器初始化过程,现在看来写的比较烂,最近又继续阅读spring源码,对IOC容器的初始化有了一些新的认识,因此决定记录下来,加深自己对spring的印象与理解. ...

  10. IO 模型 IO 多路复用

    IO 模型 IO 多路复用 IO多路复用:模型(解决问题的方案) 同步:一个任务提交以后,等待任务执行结束,才能继续下一个任务 异步:不需要等待任务执行结束, 阻塞:IO阻塞,程序卡住了 非阻塞:不阻 ...