显然,题面明摆着让你写一个可持久化 AC 自动机。

但是从空间来说这是不可能的。

想起做 不强制在线 的可持久化数据结构的一种方法,建立“时光树”,具体来说,假若版本 \(x\) 由版本 \(y\) 更改而来,建边 \(x \to y\)。最后在建出的树上遍历并回答询问。

到此我们只需要一个可以支持加入和撤销的 AC 自动机即可。

考虑维护失配树,具体来说,一个字符串出现的次数等于其所有前缀节点在失配树上的祖先中终止节点数量之和,这是一个点修链查,将其转变为子树修单点查,用树状数组维护即可。

#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;
const int maxn = 1e6+5;
class AC_automaton{
public:
int son[maxn][26],fail[maxn],rt,tot,dfncnt;
vector<int> edge[maxn];//fail 树
vector<int> fa[maxn];//原树上的祖先
int L[maxn],R[maxn],len,now;
void insert(string &s,int pos){
len=s.size(),now=rt;
for(int i=0;i<len;i++){
if(son[now][s[i]-'a']==0) son[now][s[i]-'a']=++tot;
now=son[now][s[i]-'a'];
fa[pos].push_back(now);
}
}
void build(){
queue<int> q;
for(int i=0;i<26;i++) if(son[rt][i]) fail[son[rt][i]]=rt,q.push(son[rt][i]);
while(q.size()>0){
int u=q.front();
q.pop();
for(int i=0;i<26;i++){
if(son[u][i]){
fail[son[u][i]]=son[fail[u]][i];
q.push(son[u][i]);
}
else son[u][i]=son[fail[u]][i];
}
}
for(int i=1;i<=tot;i++){
edge[fail[i]].push_back(i);
}
}
inline void dfs(int u){
L[u]=++dfncnt;
for(int v:edge[u]){
if(!L[v]) dfs(v);
}
R[u]=dfncnt;
}//处理子树信息
}AC;
int tr[maxn];
inline void add(int x,int v){
while(x<=AC.dfncnt) tr[x]+=v,x+=lowbit(x);
}
inline int pre(int x){
int res=0;
while(x>0) res+=tr[x],x-=lowbit(x);
return res;
}
int answer[maxn>>1];
struct Edge{
int v,nxt;
}e[maxn];
int head[maxn>>1],cnt;
void add_edge(int u,int v){
e[++cnt].v=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
vector<int> Query[maxn>>1];
bitset< 500005 > opt;
inline void dfs(int u){
for(int now:Query[u]){
for(int u:AC.fa[now]){
answer[now]+=pre(AC.L[u]);
}
}
Query[u].clear();
for(int i=head[u];i;i=e[i].nxt){
int now=e[i].v;
if(opt[now]==1){
add(AC.L[AC.fa[now].back()],1);
add(AC.R[AC.fa[now].back()]+1,-1);
}
dfs(now);
if(opt[now]==1){
add(AC.L[AC.fa[now].back()],-1);
add(AC.R[AC.fa[now].back()]+1,1);
}
}
}
inline int found(int u){
return tr[u]==u?u:tr[u]=found(tr[u]);
}
int q;
int main(){
cin>>q;
for(int i=1;i<=q;i++){
tr[i]=i;
int lst,op;
string s;
cin>>op>>lst>>s;
opt[i]=(op==1?1:0);
lst=found(lst);
AC.insert(s,i);
if(opt[i]==1) add_edge(lst,i);
else Query[lst].push_back(i),tr[i]=lst;
}
for(int i=0;i<=q;i++) tr[i]=0;
AC.build();
AC.dfs(AC.rt);
dfs(0);
for(int i=1;i<=q;i++) if(opt[i]==0) cout<<answer[i]<<'\n';
return 0;
}

P8451 题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

  10. JSOI2016R3 瞎BB题解

    题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...

随机推荐

  1. nim 6. 使用包

    本来想按照制作包 - 发布包 - 使用包的顺序写.发现制作包一时还没搞懂,先看看怎么使用包吧. nim的包管理工具,是自带的 nimble.  nimble的官方包列表是:Nim package di ...

  2. FileInputStream和FileOutputStream

    FileInputstream 字节输入流 用于文件内容的读取操作. 创建FileInputstream对象用于读取文件内容,使用后需要进行关闭操作 常用方法: read(); //每次仅读取一个字节 ...

  3. 题解:CF1956A Nene's Game

    这道题其实挺有意思,多测里面还套了个多测. 思路就是用向量模拟删除过程,具体请看代码里的注释. #include <bits/stdc++.h> using namespace std; ...

  4. python 日志 logging模块详解

    1.基本使用 配置logging基本的设置,然后在控制台输出日志, import logging logging.basicConfig(level=logging.INFO, format='%(a ...

  5. js 数组按指定字段转map-list结构

    js 数组按指定字段转map-list结构 背景介绍 在开发过程中经常会出现接口返回整个数组,我们需要将数组进行二次处理,如下格式按照不同功能模块(type)进行数据拆分 原始数据 const lis ...

  6. 使用Chrome 开发者工具提取对应的字符串

    最近在查看一个API的数据,效果很好,但是里面只有一部分我想要的内容 如果是简单一点的可以直接获取 如下比如我想要提取返回的代码中关键的字符串:"video": "这里的 ...

  7. C# wpf 使用 polyline 做一个贪吃蛇游戏的小蛇移动吃食部分功能

    wpf中 polyline 里有一个存放Point的集合,方向靠蛇头的前两个点的向量旋转控制.我发现,靠计算向量来旋转十分的方便.蛇的移动,就是按照蛇头计算的向量,加一个移动长度,然后得到新的点,然后 ...

  8. 你好Avalonia框架

    https://docs.avaloniaui.net/docs/getting-started/ 起因公司事业部是做移动等营业厅办理相关业务,无纸化系统的.简单的说就是以前去营业厅办理业务都需要各种 ...

  9. vivo 制品管理在 CICD 落地实践

    作者:vivo 互联网效能平台团队 - Chen Lingling 在DevOps实践中,制品管理是一个重要的组成部分,它可以帮助团队快速交付高质量.高可靠性的软件,本文将介绍在 DevOps 领域, ...

  10. Mysql 使用 group by 不对 null 做分组

    在项目开发查询数据需要将相同的数据做合并处理,但是字段为null,不做合并. 创建表以及添加数据 create table t_student( `id` int not null primary k ...