题面

CF163E e-Government

给 \(n\) 个字符串 \(s_i\) 和 \(q\) 个询问,刚开始字符串都服役。每次操作将集合中的一个字符串设为退役或服役,或查询与文本串 \(S_i\) 的匹配的服役字符串总次数。

数据范围:\(1\le n,q\le 10^5\),\(1\le \sum|s_i|,\sum|S_i|\le 10^6\)。


蒟蒻语

这是个AC自动机的套路题,但是毕竟套路巧妙而且不得不学,所以蒟蒻写一篇题解。


蒟蒻解

当这题的字符串不退役时,这就是AC自动机的模板。

回忆一下蒟蒻们是怎么做的:先建一棵Trie树,在有字符串终止节点的位置 \(tag=1\)。然后考虑到包含一个字符串必然包含一个字符串的后缀,建立 \(fail\) 链成为AC自动机,\(fail\) 链连接节点成为 \(parent\) 树,重算一个节点的 \(tag\) 为它在 \(parent\) 树上到根节点的路径上的节点的 \(tag\) 之和。每次匹配的时候,在AC自动机上跑一遍文本串,累计一下 \(tag\) 即可。

让一个字符串退役,就相当于将该字符串在Trie树上的终止节点 \(p\) 的 \(tag=1\) 变成 \(tag=0\)。建AC自动机重算 \(tag\) 的时候,每个在 \(parent\) 树上到根节点的路径上包含 \(p\) 的节点的 \(tag\) 都会减 \(1\)。容易发现 \(tag\) 减了 \(1\) 的节点,正好就是 \(parent\) 树上 \(p\) 的子树。

这时候就可以做了,巨佬可以写个树链剖分或LinkCutTree。但是考虑到这题只需要操作子树,不需要操作链,所以可以不写轻重链剖分,求每个节点的 \(dfs\) 序及其子树的 \(dfs\) 序区间即可。区间修改、单点查询可以用差分加树状数组。

当然这题有很多细节,而且代码很长,估计能写写调调好久……看蒟蒻代码吧。


代码

#include <bits/stdc++.h>
using namespace std; //Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair(a,b)
#define x first
#define y second
#define be(a) a.begin()
#define en(a) a.end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f; //Data
const int N=1e5,M=1e6+1;
int n,at[N];
bool vis[N]; //FenwickTree
int c[M+2];
void add(int x,int v){
for(int i=x+1;i<M+2;i+=i&-i) c[i]+=v;
}
int sum(int x){
int res=0;
for(int i=x+1;i>=1;i-=i&-i) res+=c[i];
return res;
} //ACAM
int cnt=1,ch[M][26];
void insert(int x,string&s){
int p=0;
for(int i=0;i<sz(s);i++){
int c=s[i]-'a';
if(!~ch[p][c]) ch[p][c]=cnt++;
p=ch[p][c];
}
at[x]=p; //记录第x个字符串的终止节点,方便查找dfs序
}
int fa[M],ind,ld[M],rd[M];//[ld,rd)是自动机节点的子树dfs序区间,ld正好是该节点的dfs序
vector<int> e[M];
void Dfs(int p){
ld[p]=ind++;
for(int v:e[p]) Dfs(v);
rd[p]=ind;
}
void build(){
queue<int> q;
for(int c=0;c<26;c++)
if(~ch[0][c]){
fa[ch[0][c]]=0;
e[0].pb(ch[0][c]); //加边建parent树
// cout<<0<<"->"<<ch[0][c]<<'\n';
q.push(ch[0][c]);
} else ch[0][c]=0;
while(sz(q)){
int p=q.front(); q.pop();
for(int c=0;c<26;c++)
if(~ch[p][c]){
fa[ch[p][c]]=ch[fa[p]][c];
e[fa[ch[p][c]]].pb(ch[p][c]); //加边建parent树
// cout<<fa[ch[p][c]]<<"->"<<ch[p][c]<<'\n';
q.push(ch[p][c]);
} else ch[p][c]=ch[fa[p]][c];
}
Dfs(0);
} //Main
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T; cin>>T>>n;
for(int p=0;p<M;p++){
fa[p]=-1;
for(int c=0;c<26;c++) ch[p][c]=-1;
}
for(int i=0;i<n;i++){
string s; cin>>s;
insert(i,s);
}
build();
for(int i=0;i<n;i++) //刚开始字符串都服役
vis[i]=1,add(ld[at[i]],1),add(rd[at[i]],-1);
while(T--){
char c; cin>>c;
if(c=='+'){
int i; cin>>i,--i;
if(vis[i]) continue;
vis[i]=1,add(ld[at[i]],1),add(rd[at[i]],-1);
} else if(c=='-'){
int i; cin>>i,--i;
if(!vis[i]) continue;
vis[i]=0,add(ld[at[i]],-1),add(rd[at[i]],1);
} else if(c=='?'){
string s; cin>>s;
int res=0,p=0;
for(int i=0;i<sz(s);i++){
int c=s[i]-'a';
p=ch[p][c],res+=sum(ld[p]);
}
cout<<res<<'\n';
}
}
return 0;
}

祝大家学习愉快!

题解-CF163E e-Government的更多相关文章

  1. ICPC — International Collegiate Programming Contest Asia Regional Contest, Yokohama, 2018–12–09 题解

    目录 注意!!此题解存在大量假算法,请各位巨佬明辨! Problem A Digits Are Not Just Characters 题面 题意 思路 代码 Problem B Arithmetic ...

  2. Emergency Evacuation 题解

    The Japanese government plans to increase the number of inbound tourists to forty million in the yea ...

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

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

  4. noip2016十连测题解

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

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

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

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

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

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

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

  8. 2016ACM青岛区域赛题解

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

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

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

随机推荐

  1. 位图bitmap应用

    所有比特的编号方法是,从低字节的低位比特位开始,第一个bit为0,最后一个bit为 n-1. 比如说,现在有个数组是这样子的,int a[4],那么a[0]的比特位为0--31a[1]的比特位为32- ...

  2. 剑指offer刷题(Tree)

    开篇 二刷剑指offer了,本来用Tyora记的笔记,发现字数到四万了就变得好卡o(╥﹏╥)o,刚好开始写博客,就转过来吧,记下来子自己看.不废话,开刷... JZ26. 树的子结构 输入两棵二叉树A ...

  3. python之 栈与队列

    忍不住想报一句粗口"卧槽"这尼玛python的数据结构也太特么方便了吧 想到当初学c语言的数据结构的时候,真的是一笔一划都要自己写出来,这python尼玛直接一个模块就ok 真的是 ...

  4. rgw前端替换civetweb为beast

    前言 ceph的rgw现在提供了两种前端, civetweb和beast 配置 修改配置文件 rgw_frontends = civetweb port=7481 为 rgw frontends = ...

  5. Java 中常见的细粒度锁实现

    上篇文章大致说了下 ReentrantLock 类的使用,对 ReentrantLock 类有了初步的认识之后让我们一起来看下基于 ReentrantLock 的几种细粒度锁实现. 这里我们还是接着用 ...

  6. 深度分析:Java虚拟机类加载机制、过程与类加载器

    虚拟机类加载机制是把描述类的数据从 Class 文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型. ​ 需要注意的是 Java 语言与其他编译时需要进 ...

  7. Java基础教程——Set

    Set·无序,不重复 HashSet 特点:没有重复数据,数据不按存入的顺序输出. HashSet由Hash表结构支持.不支持set的迭代顺序,不保证顺序. 但是Hash表结构查询速度很快. 创建集合 ...

  8. 一篇文章彻底搞懂Java的大Class到底是什么

    作者在之前工作中,面试过很多求职者,发现有很多面试者对Java的 Class 搞不明白,理解的不到位,一知半解,一到用的时候,就不太会用. 因为自己本身以前刚学安卓的时候,甚至做安卓2,3年后,也是对 ...

  9. [题解] 洛谷 P3393 逃离僵尸岛

    题目TP门 很明显是一个最短路,但是如何建图才是关键. 对于每一个不可遍历到的点,可以向外扩散,找到危险城市. 若是对于每一个这样的城市进行搜索,时间复杂度就为\(O(n^2)\),显然过不了.不妨把 ...

  10. 如何使用Python 进行数据可视化

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 在进行数据分析的时候,经常需要将数据进行可视化,以方便我们对数据的认识和理解. 0,Matplotl ...