题面

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. mdtest测试工具

    软件介绍 mdstest是软件的元数据操作基准测试工具,用来模拟对文件或者目录的open.stat.close操作,然后报告性能 下载软件压缩包: yum install openmpi openmp ...

  2. 5、Spring Boot缓存

    1.JSR107 Java Caching定义了5个核心接口,分别是CachingProvider.CacheManager.Cache.Entry.Expiry. CachingProvider:定 ...

  3. 06、MyBatis 逆向工程

    1.MyBatis逆向简介   mybatis需要程序员自己编写sql语句,mybatis官方提供逆向工程,可以针对单表自动生成mybatis执行所需要的代码(mapper.java.mapper.x ...

  4. WIN10—更改电脑桌面路径

    电脑默认的桌面路径一般都在C盘,而我们又特别喜欢把文件都放在桌面,因为桌面既方便又好找.可时间久了,桌面文件会越来越多,C盘空间会越来越小,会拖慢系统速度.怎么把系统桌面路径设置在非C盘呢?本期教程将 ...

  5. Android10_原理机制系列_AMS(ATMS)之应用的第一次启动的过程

    概述 该篇基于Android 10的代码.在 AMS之AMS的启动---Android Framework(Android 10) 中已经介绍了,在Android 10中,activity的调度和管理 ...

  6. kali 系列学习12-使用Wifite破解无线网络

    一些破解无线网络程序是使用Aircrack-ng工具集,并添加了一个图形界面或使用文本菜单的形式来破解无线网络.这使得用户使用它们更容易,而且不需要记住任何命令.本节将介绍使用命令行工具Wifite, ...

  7. php读取Excel文件数据

    首先先下载 PHPExcel 脚本之家下载地址:https://www.jb51.net/codes/194070.html 然后把文件丢到php脚本同级目录里面 在php文件里面写下以下代码即可 & ...

  8. webug第十四关:存储型XSS

    第十四关:存储型XSS 打开发现是评论区 留言加入xss语句

  9. Redis设计与实现一之简单的动态字符串

    简单的动态字符串 Redis没有直接使用C语言中的字符串,而是自己构建了SDS这样的一种简单动态字符串,并且将他作为Redis中字符串的默认的表示. 但是并未完全抛弃C语言字符串,只不过是在C语言字符 ...

  10. 【P1972】HH的项链——树状数组+询问离线

    (题面摘自luogu) 题目背景 无 题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断地收集 ...