CF 163E. e-Government ac自动机+fail树+树状数组
题目:
给出n个字符串,表示n个人名,有两种操作:
?string ,统计字符串string中出现的属于城市居民的次数。
+id,把编号为id的人变为城市居民,如果已经是忽略。
-id,把编号为id的人变为不是城市居民,如果已经不是的话忽略。
现有m个操作,对于?输出结果。
分析:
很容易想到建立ac自动机,+-操作倒简单,使用bool数组标记一下即可。对于每个询问,每次都沿着fail指针往上走,遇到了标记为城市居民的字符串时加1,否则继续往上走。
在这显然会TLE。很容易构造出以下数据:
a
aa
aaa
...
aaa...aaa
?aaa...aaa
考虑把fail指针反向,由于ac自动机的每个节点均有唯一的fail指针,若是沿着fail指针往上走,显然都会走到root,所以反向之后显然是一棵树,不妨称之为fail树。
fail树有什么特点呢?可以画个图试试,如果儿子节点出现过,那么他的祖先显然也会出现!因此,我们统计某个节点时,实际上就是统计在fail树中该节点到根的所有节点出现过的总次数。怎么统计?这不就是用dfs序维护树状数组吗?于是这题得以解决。每次寻找的时间复杂度为O(len*log)的级别。
#include <set>
#include <map>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; typedef long long ll;
typedef unsigned long long ull; #define debug puts("here")
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define foreach(i,vec) for(unsigned i=0;i<vec.size();i++)
#define pb push_back
#define RD(n) scanf("%d",&n)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w)
#define All(vec) vec.begin(),vec.end()
#define MP make_pair
#define PII pair<int,int>
#define PQ priority_queue
#define cmax(x,y) x = max(x,y)
#define cmin(x,y) x = min(x,y)
#define Clear(x) memset(x,0,sizeof(x))
//#pragma comment(linker, "/STACK:1024000000,1024000000") /******** program ********************/ const int MAXN = 1.5e6;
const int kind = 26; char s[MAXN];
bool use[MAXN]; struct BIT{
int c[2*MAXN];
inline void init(){
Clear(c);
}
inline int lowbit(int x){
return x & -x;
}
inline void update(int x,int y,int val){
modify(x,val);
modify(y,-val);
}
inline void modify(int x,int val){
if(x==0)return;
while(x<MAXN){
c[x] += val;
x += lowbit(x);
}
}
inline int ask(int x){
int ans = 0;
while(x>0){
ans += c[x];
x -= lowbit(x);
}
return ans;
}
}bit; struct AC{
int ch[MAXN][kind],fail[MAXN];
int tot;
vector<int> adj[MAXN];
int low[MAXN],dfn[MAXN],tol;
int at[MAXN]; inline void set(int x){
Clear(ch[x]);
fail[x] = 0;
} inline void init(){
rep(i,MAXN)
adj[i].clear();
set(1);
tot = 1;
tol = 0;
} inline int newNode(){
set(++tot);
return tot;
} inline int ind(char c){
return c-'a';
} inline void insert(int id){
int r = 1;
for(int i=0;s[i];i++){
int c = ind(s[i]);
if(ch[r][c]==0)
ch[r][c] = newNode();
r = ch[r][c];
}
at[id] = r;
} inline void build(){
queue<int> q;
q.push(1);
while(!q.empty()){
int r = q.front();
q.pop();
if(fail[r])
adj[ fail[r] ].pb(r);
rep(c,kind){
int x = ch[r][c];
if(!x)continue;
q.push(x); int y = fail[r];
while(y&&ch[y][c]==0)
y = fail[y];
fail[x] = y?ch[y][c]:1;
}
}
} void dfs(int x){
low[x] = ++tol;
foreach(i,adj[x])
dfs(adj[x][i]);
dfn[x] = tol;
} inline void run(){
int len = strlen(s)-1;
int ans = 0; int r = 1;
rep1(i,len){
int c = ind(s[i]);
while(r&&ch[r][c]==0)
r = fail[r];
if(r) r = ch[r][c];
else r = 1;
ans += bit.ask( low[r] );
} printf("%d\n",ans);
} }ac; void cc(int x,int val){
bit.update( ac.low[ ac.at[x] ],1+ac.dfn[ ac.at[x] ],val );
} int main(){ #ifndef ONLINE_JUDGE
freopen("sum.in","r",stdin);
//freopen("sum.out","w",stdout);
#endif int n,m;
while(cin>>m>>n){
ac.init();
bit.init(); rep1(i,n){
scanf("%s",s);
ac.insert(i);
use[i] = true;
} ac.build();
ac.dfs(1); rep1(x,n)
cc(x,1); int x;
while(m--){
scanf("%s",s);
if(s[0]=='?')
ac.run();
else{
sscanf(s+1,"%d",&x);
if(use[x]&&s[0]=='-'){
use[x] = 0;
cc(x,-1);
}else if(!use[x]&&s[0]=='+'){
use[x] = 1;
cc(x,1);
}
}
}
} return 0;
}
CF 163E. e-Government ac自动机+fail树+树状数组的更多相关文章
- CF G. Indie Album AC自动机+fail树+线段树
这个套路挺有意思的. 把 $trie$ 和 $fail$ 树都建出来,然后一起跑一跑就好了~ #include <queue> #include <cstdio> #inclu ...
- CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)
The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...
- AC自动机fail树上dfs序建线段树+动态memset清空
题意:http://acm.hdu.edu.cn/showproblem.php?pid=4117 思路:https://blog.csdn.net/u013306830/article/detail ...
- AC自动机——1 Trie树(字典树)介绍
AC自动机——1 Trie树(字典树)介绍 2013年10月15日 23:56:45 阅读数:2375 之前,我们介绍了Kmp算法,其实,他就是一种单模式匹配.当要检查一篇文章中是否有某些敏感词,这其 ...
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2545 Solved: 1419[Submit][Sta ...
- BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]
3172: [Tjoi2013]单词 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3198 Solved: 1532[Submit][Status ...
- 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序
3881: [Coci2015]Divljak Time Limit: 20 Sec Memory Limit: 768 MBSubmit: 508 Solved: 158[Submit][Sta ...
- BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)
题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...
- 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2022 Solved: 1158[Submit][Sta ...
随机推荐
- 【转】google推出的SwipeRefreshLayout下拉刷新用法
SwipeRefreshLayout是Google在support v4 19.1版本的library更新的一个下拉刷新组件,实现刷新效果更方便. 使用如下: 1.先下载android-support ...
- C++100款开源界面库[转]
(声明:Alberl以后说到开源库,一般都是指著名的.或者不著名但维护至少3年以上的.那些把代码一扔就没下文的,Alberl不称之为开源库,只称为开源代码.这里并不是贬低,像Alberl前面那个系列的 ...
- js中的call及apply
http://www.zhihu.com/question/20289071 func1.call(this, arg1, arg2); 或者 func1.apply(this, [arg1, arg ...
- PHP中关于超链接的拼接问题
<?php$link = " http://www.baidu.com";echo '<a href='.$link.'> 百度 </a>';?> ...
- C++ 方法隐藏
1.过载:一个类中,方法名相同,形参表不同的方法. 2.重写:子类与父类的virtual方法,方法名,形参表相同. 3.考虑下面的情况,子类与父类方法名相同. 父类是virtual方法 ...
- 关于OPenGL和OSG的矩阵 (转)
关于OPenGL和OSG的矩阵 矩阵真的是一个很神奇的数学工具, 虽然单纯从数学上看, 它并没有什么特别的意义, 但一旦用到空间中的坐标变换,它就“一遇风云便成龙”, 大显神威了.简单的工具实现了复杂 ...
- Java 完美判断中文字符的方法
Java判断一个字符串是否有中文一般情况是利用Unicode编码(CJK统一汉字的编码区间:0x4e00–0x9fbb)的正则来做判断,但是其实这个区间来判断中文不是非常精确,因为有些中文的标点符号比 ...
- 剑指 offer set 9 包含min函数的栈
总结 1. 要求栈的 push, pop, min 都是 o(1). 普通栈支持 Push Pop 操作, 且时间复杂度已为 o(1), 再加上 Min 函数, 时间复杂度已无法优化, 只能通过加空间 ...
- Tcsh脚本编程
Tcsh主要用于Free BSD等UNIX系统中. 一.输出字符串Hello的示例脚本 Tcsh脚本的基本格式.编写方法及脚本中使用的命令等,与Bash脚本完全相同,只需要直接套用即可. [root@ ...
- android genymation eclipse安装
http://www.cnblogs.com/1114250779boke/p/3657996.html