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. linux tail命令的使用方法详解 (转载)

    本文介绍Linux下tail命令的使用方法.linux tail命令用途是依照要求将指定的文件的最后部分输出到标准设备,通常是终端,通俗讲来,就是把某个档案文件的最后几行显示到终端上,假设该档案有更新 ...

  2. js 原型的内存分析

    使用构造器的弊端:http://www.cnblogs.com/a757956132/p/5258897.html 示例 将行为设置为全局的行为,如果将所有的方法都设计为全局函数的时候, 这个函数就可 ...

  3. jquery调用页面的方法

    本文转载:http://www.cnblogs.com/chenxizhang/archive/2009/05/28/1491250.html 有些朋友问到,能不能在jquery代码中调用后台cs页面 ...

  4. MON166 User's Guide

    MON166 is a debug monitor for C16x and ST10 user programs. It consists of: A configurable monitor pr ...

  5. 四月二十五日,bugzilla for CentOS 安装

    Bugzilla for CentOS 5.4 制作人,陈浩 时间:2014.4.25 原创 文件夹 Bugzilla for CentOS 5.4 一. 装系统 1) 新建虚拟机  15G硬盘,51 ...

  6. NAVICATE 修改存储过程提示PROCEDURE _Navicat_Temp_Stored_Proc already exists 解决方法

    推测是navicate修改存储过程会自动名为_Navicat_Temp_Stored_Proc的存储过程 创建完毕后自动drop 由于某些原因或bug导致最终没有drop,于是修改存储过程失败. 所以 ...

  7. 如何实现一个c/s模式的flv视频点播系统

    一.写在前面 视频点播,是一个曾经很热,现如今依然很热的一项视频服务技术.本人最近致力于研究将各种视频格式应用于点播系统中,现已研究成功FLV, F4V, MP4, TS格式的视频点播解决方案,完全支 ...

  8. [ES6] 15. Generators -- 2

    Using for..of statement: function* greeting(){ console.log(`Generators are "lazy"`); yield ...

  9. [MongoDB] Query, update, index and group

    /* 1. Query Operators */ db.posts.find({ viewsCount: {$get: 1000, $lte: 3000} }, {_id: 0, viewsCount ...

  10. 分享一款页面视差滚动切换jquery.localscroll插件

    今天给大家分享一款页面视差滚动切换jquery.localscroll插件. 滚动鼠标液动条看下页面的切换效果.该插件适用浏览器:IE8.360.FireFox.Chrome.Safari.Opera ...