这个套路挺有意思的.

把 $trie$ 和 $fail$ 树都建出来,然后一起跑一跑就好了~

#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define N 500004
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
struct Seg {
#define lson (now<<1)
#define rson (now<<1|1)
int sum[N<<2];
void update(int l,int r,int now,int p,int v) {
sum[now]+=v;
if(l==r) return;
int mid=(l+r)>>1;
if(p<=mid) update(l,mid,lson,p,v);
else update(mid+1,r,rson,p,v);
}
int query(int l,int r,int now,int L,int R) {
if(l>=L&&r<=R) return sum[now];
int mid=(l+r)>>1,re=0;
if(L<=mid) re+=query(l,mid,lson,L,R);
if(R>mid) re+=query(mid+1,r,rson,L,R);
return re;
}
}seg;
struct Trie {
int c,to;
Trie(int c=0,int to=0):c(c),to(to){}
};
struct Node {
int ch[27];
}t[N];
struct AC {
int ch[27],f;
}a[N];
struct Q {
int i,id;
Q(int i=0,int id=0):i(i),id(id){}
};
queue<int>q;
vector<Q>G[N];
vector<Trie>T[N];
char S[N];
int n,tot,m,edges,tim,siz[N],tot2,id[N],endd[N],hd[N],nex[N],to[N],dfn[N],answer[N];
inline void add(int u,int v) {
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
inline void insert(int x) {
int rt=0,len=strlen(S+1),i;
for(i=1;i<=len;++i) {
if(!a[rt].ch[S[i]-'a']) a[rt].ch[S[i]-'a']=++tot2;
rt=a[rt].ch[S[i]-'a'];
}
endd[x]=rt;
}
inline void buildAC() {
for(int i=0;i<27;++i) if(a[0].ch[i]) q.push(a[0].ch[i]);
while(!q.empty()) {
int u=q.front(),i;
q.pop();
for(i=0;i<27;++i) {
int p=a[u].ch[i];
if(!p) {
a[u].ch[i]=a[a[u].f].ch[i];
continue;
}
a[p].f=a[a[u].f].ch[i];
q.push(p);
}
}
}
void dfs(int u) {
siz[u]=1,dfn[u]=++tim;
for(int i=hd[u];i;i=nex[i]) {
dfs(to[i]),siz[u]+=siz[to[i]];
}
}
inline void build_tree() {
int i,j;
for(i=1;i<=tot2;++i) add(a[i].f,i);
dfs(0);
}
void solve(int now,int x) {
seg.update(1,tim,1,dfn[now],1);
for(int i=0;i<G[x].size();++i) {
answer[G[x][i].i]=seg.query(1,tim,1,dfn[G[x][i].id],dfn[G[x][i].id]+siz[G[x][i].id]-1);
}
for(int i=0;i<T[x].size();++i) {
solve(a[now].ch[T[x][i].c],T[x][i].to);
}
seg.update(1,tim,1,dfn[now],-1);
}
int main() {
int i,j;
// setIO("input");
scanf("%d",&n);
for(i=1;i<=n;++i) {
int op,x,lst=0;
char str[2];
scanf("%d",&op);
if(op==2) scanf("%d",&lst),lst=id[lst];
scanf("%s",str);
if(!t[lst].ch[str[0]-'a']) {
t[lst].ch[str[0]-'a']=++tot;
id[i]=t[lst].ch[str[0]-'a'];
T[lst].push_back(Trie(str[0]-'a',id[i]));
}
else id[i]=t[lst].ch[str[0]-'a'];
}
scanf("%d",&m);
for(i=1;i<=m;++i) {
scanf("%d%s",&j,S+1),insert(i),G[id[j]].push_back(Q(i, endd[i]));
}
buildAC();
build_tree();
solve(0,0);
for(i=1;i<=m;++i) printf("%d\n",answer[i]);
return 0;
}

  

CF G. Indie Album AC自动机+fail树+线段树的更多相关文章

  1. CF G. Indie Album 广义后缀自动机+树链剖分+线段树合并

    这里给出一个后缀自动机的做法. 假设每次询问 $t$ 在所有 $s$ 中的出现次数,那么这是非常简单的: 直接对 $s$ 构建后缀自动机,随便维护一下 $endpos$ 大小就可以. 然而,想求 $t ...

  2. bzoj 2434 AC自动机 + fail指针建树 + 树状数组

    思路:我们先跟着它给定的字符串走把字典树建出来,求出fail指针,我们考虑两个字符串 A和B, 如果想要求B中有多少A的子串,转换一下就是有多少个B的前缀的后缀包含A,这个在AC自动机 的状态图中很容 ...

  3. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

  4. Codeforces 1207 G. Indie Album

    Codeforces 1207 G. Indie Album 解题思路 离线下来用SAM或者AC自动机就是一个单点加子树求和,套个树状数组就好了,因为这个题广义SAM不能存在 \(len[u] = l ...

  5. 2021.11.09 P4824 [USACO15FEB]Censoring S与P3121 [USACO15FEB]Censoring G(KMP&&AC自动机)

    2021.11.09 P4824 [USACO15FEB]Censoring S与P3121 [USACO15FEB]Censoring G(KMP&&AC自动机) https://w ...

  6. [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)

    题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...

  7. 【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并

    题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r ...

  8. 浅谈树套树(线段树套平衡树)&学习笔记

    0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...

  9. CodeForces - 1207G :Indie Album(AC自动机 fail树上DFS)

    题意:有N个串,给出的形式是拼接给出,对于第i行:  (1,c)表示字符串i是单个字母c: (2,p,c)表示字符串i=在字符串p后面接上一个字母c. 然后给出M个提问,形式是(i,string).问 ...

随机推荐

  1. Python之模块IO

    目录 Python之模块IO io概叙 io类层次结构 io模块的类图 io模块的3种I/O 原始I/O,即RawIOBase及其子类 文本I/O,即TextIOBase及其子类 字节I/O(缓存I/ ...

  2. Linux系统定时备份网站文件到七牛云存储脚本

    1.七牛云账号注册. 有些朋友可能会问为什么要备份到七牛云?很简单,七牛云免费注册就能获取1G的存储空间,只要简单几步操作完成实名认证即可获取10G的存储空间,对于一般个人站点来说已经足够备份使用了. ...

  3. window10提交代码到码云

    1.创建项目文件夹,例如创建一个"爬虫项目码云仓库" 2.进入项目文件夹,在地址栏输入cmd然后回车,这样就在该文件夹打开了终端 3.终端输入git init初始化项目仓库,此时会 ...

  4. 部署Flannel网络

    部署Flannel网络 部署flannel网络需要执行以下步骤: 1)写入分配的子网段到etcd,供flanneld使用 2)下载二进制包 3)配置Flannel 4)systemd管理Flannel ...

  5. 浏览器进程线程时间循环、与vue netTick的实现原理

    浏览器事件循环(结合vue nextTick)https://juejin.im/post/5cb736c5f265da039955d4e8#comment messageChanel的讲解https ...

  6. elasticsearch设置执行脚本并添加开机启动 (转)

    elasticsearch设置执行脚本并添加开机启动 在/etc/init.d目录下新建文件elasticsearch #!/bin/sh #chkconfig: 2345 80 05 #descri ...

  7. springboot启动端口占用问题,报错org.apache.catalina.LifecycleException: Protocol handler start failed

    解决办法,找到被占用的端口

  8. nfs服务的配置

    nfs服务 nfs简介 Network file system 网络文件系统.NFS server可以看作是一个 file server.它可以让你的pc通过网络将远端的nfs server共享出来的 ...

  9. 搭建CentOs7的WebServer

    CentOs7,在安装的时候,自己可以定义一些东西,包括硬盘分区,服务器角色等. 这一些就搭了一个BasicWebServer,这样的话,里面的很多勾选,包括Java,Perl,Python,php等 ...

  10. java多线程的四种实现方式

    主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorService.Callable.Futur ...