这个套路挺有意思的.

把 $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. mysql拆分逗号一列变多行

    需求: SELECT ), ) FROM TABLE a INNER JOIN mysql.help_topic b )

  2. 算法 - k-means算法

    一.聚类思想 所谓聚类算法是指将一堆没有标签的数据自动划分成几类的方法,属于无监督学习方法,这个方法要保证同一类的数据有相似的特征,如下图所示:     根据样本之间的距离或者说是相似性(亲疏性),把 ...

  3. 【DP 好题】hihoCoder #1520 古老数字

    题目链接 这道题的要点是状态转移的顺序. 要从低位向高位进行状态转移. Implementation string s; cin >> s; reverse(all(s)); int x, ...

  4. AC自动机练习题1:地图匹配

    AC自动机板子,学习之前要是忘记了就看一下 1465: [AC自动机]地图匹配 poj1204 时间限制: 1 Sec  内存限制: 256 MB提交: 78  解决: 46[提交] [状态] [讨论 ...

  5. Python和其他编程语言

    Python和其他编程语言 一.Python介绍 Python的创始人为吉多·范罗苏姆(Guido van Rossum),如下图,少数几个不秃头的语言创始人.1989年的圣诞节期间,Guido为了打 ...

  6. WPF使用资源图片

    一.加载本项目的图片 WPF引入了统一资源表示Uri来标识和访问资源.其中较为常见的情况是用Uri加载图像.Uri表达式的一把形式为:协议+授权+路径 协议:pack:// 授权:有两种,一种用于访问 ...

  7. 数据库oracle一些操作(MiTAC)

    oracle计算时间差函数: 两个Date类型字段:START_DATE,END_DATE,计算这两个日期的时间差(分别以天,小时,分钟,秒,毫秒): 天: ROUND(TO_NUMBER(END_D ...

  8. ubuntu 16.04下ssh访问提示错误

    liuyan@ubuntu:/etc/init.d$ sudo apt-get install openssh-server -yReading package lists... DoneBuildi ...

  9. Cocoapods私有库

    http://www.jianshu.com/p/d6a592d6fced 1.创建两个什么都不选的远程仓库:(私有公有都可,ReadMe\ignore都不选),一个放代码,一个放源(*.podspe ...

  10. deep_learning_Function_tf.control_dependencies([])

    tf.control_dependencies([])函数含义及使用 2019.02.23 14:01:14字数 60阅读 420 tf.control_dependencies([controls_ ...