显然,题面明摆着让你写一个可持久化 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. 一键自动化博客发布工具,用过的人都说好(oschina篇)

    oschina和segmentfault一样,界面非常的清爽. 界面上除了必须的标题,内容之外,还有文章专辑和推广专区这几个选项. 一起来看看在blog-auto-publishing-tools中, ...

  2. ansible系列(21)--ansible的变量注册Register

    1. 变量注册Register register 关键字可以将某个 task 任务结果存储至变量中,最后使用 debug模块 输出变量内容,可以用于后续排障: 示例一:register的基本使用: # ...

  3. 使用c#强大的表达式树实现对象的深克隆

    一.表达式树的基本概念 表达式树是一个以树状结构表示的表达式,其中每个节点都代表表达式的一部分.例如,一个算术表达式 a + b 可以被表示为一个树,其中根节点是加法运算符,它的两个子节点分别是 a ...

  4. 改造 Kubernetes 自定义调度器

    原文出处:改造 Kubernetes 自定义调度器 | Jayden's Blog (jaydenchang.top) Overview Kubernetes 默认调度器在调度 Pod 时并不关心特殊 ...

  5. gossh nohup部署退出解决方法

    ssh 会话远程nohup ./node> node.out & 执行指令,会话退出以后也会导致服务并没有部署成功. 应该使用以下命令:nohup ./node > node.ou ...

  6. C# wpf之控制屏幕显示方向旋转

    using System;using System.Collections.Generic;using System.Linq;using System.Runtime.InteropServices ...

  7. WPF实现轮播图

    1.效果图 2.前端代码 <Window x:Class="LiveChartDemo.View.CarouselView" xmlns="http://schem ...

  8. 我用docker搭建的第一个博客

    其实很早就听说了docker这个东西,一直以来想玩不知道拿什么下手,再加上前段时间听了一个思科的年度网络报告讲解里面稍微提了一下docker的优势以及网络即服务的概念.想通了,不是每一步都得亲历亲为, ...

  9. JVM面试篇(下)

    垃圾收集器 简述 Java 垃圾回收机制 在 java 中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行.在 JVM 中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行 ...

  10. 搭建高可用k8s

    搭建k8s高可用 高可用只针对于api-server,需要用到nginx + keepalived,nginx提供4层负载,keepalived提供vip(虚拟IP) 系统采用openEuler 22 ...