题面

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. InnoDB Insert Buffer(插入缓冲 转)

    一,插入缓冲(Insert Buffer/Change Buffer):提升插入性能 只对于非聚集索引(非唯一)的插入和更新有效,对于每一次的插入不是写到索引页中,而是先判断插入的非聚集索引页是否在缓 ...

  2. 重要 | Spark分区并行度决定机制

    最近经常有小伙伴在本公众号留言,核心问题都比较类似,就是虽然接触Spark有一段时间了,但是搞不明白一个问题,为什么我从HDFS上加载不同的文件时,打印的分区数不一样,并且好像spark.defaul ...

  3. bootstrap-datetimepicker 编辑回显

    官网上居然没给出解决方案....汗 stackoverflow给出了灵感: $("#dateOfManufacture").find("input").val( ...

  4. 基于udp的scoket通信

    1.udp例子1 udpserver.py # udp的server,不需要进行监听也不需要建立连接 # 在启动服务之后只能被动的等待客户端发送消息过来 # 客户端发送消息的同时还会自带地址信息 # ...

  5. IDEA 使用的一些快捷键记录

    1,ctrl+tab 导航当前编辑打开的所有文件,按住Ctrl,使用backspace 可以关闭某个文件 2,ctrl+shift+alt+s 打开项目设置,alt+shift+s 打开所有设置 3, ...

  6. Bugku-cms1

    一.先用御剑扫描 二.点击第一个目录,发现sql文件 三.把它载下来,用Notepad++打开.发现管理员的账号和密码(admin的密码好像被人改了,然后我用admin888登的后台)  四.后台地址 ...

  7. FL studio系列教程(八):如何打开和新建FL Studio的文件

    FL Studio编曲软件中制作和编辑的音乐将存储在FL Studio的项目文件中.我们随时都可以打开这些对项目文件进行二次编辑和修改等等.操作的方法同很多软件都相同,但也有其独特的地方.下面就跟小编 ...

  8. sql常用函数整理

    SQL中包含以下七种类型的函数: 聚合函数:返回汇总值. 转型函数:将一种数据类型转换为另外一种. 日期函数:处理日期和时间. 数学函数:执行算术运算. 字符串函数:对字符串.二进制数据或表达式执行操 ...

  9. 对于char,short和byte类型的运算

    对于char,short和byte这些类型在计算时都会提升到int型来计算,所以a+b=3(这个3是int型的,所以我们需要将它强转成为byte类型,才不会出错.但是使用 += 或者 ++ 运算符可以 ...

  10. 写代码有这16个好习惯,可以减少80%非业务的bug

    前言 每一个好习惯都是一笔财富,本文整理了写代码的16个好习惯,每个都很经典,养成这些习惯,可以规避多数非业务的bug!希望对大家有帮助哈,谢谢阅读,加油哦~ github地址,感谢每颗star ❝ ...