E. e-Government

题目:

  给出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树+树状数组的更多相关文章

  1. CF G. Indie Album AC自动机+fail树+线段树

    这个套路挺有意思的. 把 $trie$ 和 $fail$ 树都建出来,然后一起跑一跑就好了~ #include <queue> #include <cstdio> #inclu ...

  2. CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)

    The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...

  3. AC自动机fail树上dfs序建线段树+动态memset清空

    题意:http://acm.hdu.edu.cn/showproblem.php?pid=4117 思路:https://blog.csdn.net/u013306830/article/detail ...

  4. AC自动机——1 Trie树(字典树)介绍

    AC自动机——1 Trie树(字典树)介绍 2013年10月15日 23:56:45 阅读数:2375 之前,我们介绍了Kmp算法,其实,他就是一种单模式匹配.当要检查一篇文章中是否有某些敏感词,这其 ...

  5. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Sta ...

  6. BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 3198  Solved: 1532[Submit][Status ...

  7. 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序

    3881: [Coci2015]Divljak Time Limit: 20 Sec  Memory Limit: 768 MBSubmit: 508  Solved: 158[Submit][Sta ...

  8. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

  9. 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2022  Solved: 1158[Submit][Sta ...

随机推荐

  1. Android Service服务

    Service是Android系统中提供的四大组件之一.它是运行在后台的一种服务,一般声明周期较长,不直接与用户进行交互.    服务不能自己运行,需要通过调用Context.startService ...

  2. InvocationHandler

    ====================================================================== 代理类生成之后再调用目标方法时就会调用invoke方法 p ...

  3. 在js中使用createElement创建HTML对象和元素

    1.创建链接 <script language="javascript"> var o = document.body; //创建链接 function createA ...

  4. SQLServer获取随机数据

    1.比较常见和好用的一种 SELECT TOP 10 *, NEWID() AS randomFROM tableORDER BY random --newid函数会随机生成一个guid,很长的一个字 ...

  5. Painter 12安装教程

    1 首先打开激活器 2 开始安装,点击我有序列码,把激活器中的序列码粘贴到安装文件中. 3 安装完成后,点击activate option选项,点击电话联系: 激活成功

  6. perl学习笔记(2)

    1)记得刚开始写perl的时候,对于一个功能,总是拿目前能用的数据类型来解决问题,不想想有没有更好的,能用能解决问题就好,这就导致了后期,要在函数里面添加功能的时候,函数要添加很多参数,一个函数有7. ...

  7. xhtml和css概述

    Xhtml和css概述 1.html的过渡到xhtml html与xhtml不是两种语言,它们是一种语言的不同阶段,有点类似于文言文和白话文之间的关系.因为网络技术的日新月异,html的不断改进,所以 ...

  8. Mailbox and Mail

    #ifndef __MAILBOX_H__ #define __MAILBOX_H__ #include <stdint.h> #include <stdlib.h> #inc ...

  9. 学习马士兵的struts2/hibernate/spring中遇到的问题及其解决方法

    STRUTS2 1. 写好最简单的hello world项目后,无法通过浏览器访问到hello.jsp页面,提示没有资源. 学习structs2的时间,已经更新到了2.3.16了,structs中的很 ...

  10. 一个小巧的C++Log输出到文件类 (转)

      http://blog.csdn.net/dpsying/article/details/17122739 有时候需要输出一些程序运行的信息,供我们不需要调试就可以直接查看程序运行状态.所以我们需 ...