这个套路挺有意思的.

把 $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. Linux学习笔记(15)Linux字符集(locale,LANG,LC_ALL)

    关键词:linux系统修改编码,linux字符集问题, 目录  零.什么是locale 一.locale的详细内容 二.理解locale的设置 三 具体设定locale的方法(zh_CN.UTF-8. ...

  2. PostgreSQL SQL优化之NOT IN问题

    在我们平时写SQL时,如果遇到需要排除某些数据时,往往使用id <> xxx and id <> xxx,进而改进为id not in (xxx, xxx); 这样写没有问题, ...

  3. GitHub从小白到熟悉<二>

    创建 仓库  

  4. redis 学习(12)-- redis 发布订阅

    redis 发布订阅 发布订阅模式中的角色 发布者(publisher) 订阅者(subscriber) 频道(channel) 如图所示: 发布者发布消息到频道,订阅了频道的订阅者可以收到消息,订阅 ...

  5. java程序中访问https时,报 PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

    在java中使用https访问数据时报异常: Caused by: sun.security.validator.ValidatorException: PKIX path building fail ...

  6. 学习笔记--最近公共祖先(LCA)的几种求法

    前言: 给定一个有根树,若节点\(z\)是两节点\(x,y\)所有公共祖先深度最大的那一个,则称\(z\)是\(x,y\)的最近公共祖先(\(Least Common Ancestors\)),简称\ ...

  7. 103、Swarm如何管理存储数据?(Swarm10)

    参考https://www.cnblogs.com/CloudMan6/p/8000906.html   Service 的容器副本会 scale up/down ,会 failover,会在不同的主 ...

  8. replace函数更换表中字段的域名

    网站域名更换后,数据库很多链接都是存的绝对路径,这时候需要修改表里字段的路径,使用replace函数更改域名 update 表名 set 字段名 =replace(字段名 ,'旧域名','新域名') ...

  9. Java读取利用java.util类Properties读取resource下的properties属性文件

    说明:upload.properties属性文件在resources下 import java.io.IOException;import java.io.InputStream;import jav ...

  10. string 驻留机制

    string 驻留机制   string s1 = "abc"; string s2 = "ab"; string s3 = s2 + "c" ...