CF G. Indie Album AC自动机+fail树+线段树
这个套路挺有意思的.
把 $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树+线段树的更多相关文章
- CF G. Indie Album 广义后缀自动机+树链剖分+线段树合并
这里给出一个后缀自动机的做法. 假设每次询问 $t$ 在所有 $s$ 中的出现次数,那么这是非常简单的: 直接对 $s$ 构建后缀自动机,随便维护一下 $endpos$ 大小就可以. 然而,想求 $t ...
- bzoj 2434 AC自动机 + fail指针建树 + 树状数组
思路:我们先跟着它给定的字符串走把字典树建出来,求出fail指针,我们考虑两个字符串 A和B, 如果想要求B中有多少A的子串,转换一下就是有多少个B的前缀的后缀包含A,这个在AC自动机 的状态图中很容 ...
- BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)
题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...
- Codeforces 1207 G. Indie Album
Codeforces 1207 G. Indie Album 解题思路 离线下来用SAM或者AC自动机就是一个单点加子树求和,套个树状数组就好了,因为这个题广义SAM不能存在 \(len[u] = l ...
- 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 ...
- [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)
题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...
- 【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并
题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r ...
- 浅谈树套树(线段树套平衡树)&学习笔记
0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...
- CodeForces - 1207G :Indie Album(AC自动机 fail树上DFS)
题意:有N个串,给出的形式是拼接给出,对于第i行: (1,c)表示字符串i是单个字母c: (2,p,c)表示字符串i=在字符串p后面接上一个字母c. 然后给出M个提问,形式是(i,string).问 ...
随机推荐
- [转帖]DotNetCore跨平台~System.DrawingCore部署Linux需要注意的
DotNetCore跨平台~System.DrawingCore部署Linux需要注意的 https://www.bbsmax.com/A/QV5ZemYVJy/?tdsourcetag=s_pc ...
- 自然语言处理工具HanLP-N最短路径分词
本篇给大家分享baiziyu 写的HanLP 中的N-最短路径分词.以为下分享的原文,部分地方有稍作修改,内容仅供大家学习交流! 首先说明在HanLP对外提供的接口中没有使用N-最短路径分词器的,作者 ...
- Java基础(六)
面向对象 概述 生活举例 代码体验 类与对象的关系 类的定义 根据类创建对象 对象的基本使用 练习:手机类与对象 内存图:一个对象 内存图:两个对象 内存图:同一个对象 局部变量与成员变量的区别 pr ...
- FFmpeg4.0笔记:采集系统声音
Github https://github.com/gongluck/FFmpeg4.0-study/tree/master/Cff // 采集系统声音 void test_systemsound() ...
- QQ登錄實現功能
<html> <head> <title></title> </head> <body> <form> <p& ...
- JMX jconsole 的使用
JMX 1. JMX简单介绍 JMX的全称为Java Management Extensions. 顾名思义,是管理Java的一种扩展.这种机制可以方便的管理正在运行中的Java程序.常用于管理线程, ...
- js 发送异步请求
js用XMLHttpRequest发送异步请求 发送GET请求 var xhr = new XMLHttpRequest(); xhr.open('GET',url);//url为请求地址 xhr.r ...
- 线程的函数中调用MFC对话框类的变量
线程的函数中调用MFC对话框类的变量多线程传输文件的对话框 现在想要在对话框上添加一个进度条 为进度条映射变量m_progress这就需要在传输一段文件后就更新m_progress的值使进度条前进 也 ...
- SuperMap-WebGL-坐标系及转换说明
转载自:https://blog.csdn.net/supermapsupport/article/details/89519310 一.坐标系介绍我们先来列举下Cesium中的坐标系:WGS84经纬 ...
- windows下xgboost安装到python
初始环境 在安装之前,我的anaconda2已经安装好,git也有装好 下载相对应的xgboost.dll文件 下载地址 Installing the Python Wrapper for me: x ...