题意

给你一些串,还有一些询问
问你第x个串在第y个串中出现了多少次

思路

对这些串建ac自动机
根据fail树的性质:若x节点是trie中root到t任意一个节点的fail树的祖先,那么x一定是y的子串
而x在y中出现的次数为以x为fail树中的根节点的子树中,有多少个节点是trie树中根节点到y的
首先对询问离线
由于这题是一个节点一个节点建的ac自动机,所以我们可以根据这个建立的路径来维护一个当前节点到根的路径
路径上的点权为1,其余为0
每次到达一个询问到的y,我们就查询此时x的fail树中的子树和,这个可以预处理出fail树的dfs序用树状数组维护

但是如果排除这题的特殊性,要通过遍历trie的方式来更新答案
因为在操作fail的过程中,trie改变了

else trie[now][i]=trie[fail[now]][i];

也就是说bfs构造fail指针的时候,有时候会让trie指向之前的节点,也就是(trie中)高度比较小的节点
所以dfs只需要这样写

void dfs(int x){//printf("==%d\n",x);add(bg[x],1);for(int i = 0; i < (int)Q[x].size(); i++){int y = Q[x][i].fst;ans[Q[x][i].sc]=sum(ed[y])-sum(bg[y]-1);}for(int i = 0; i < 26; i++){int y = ac.trie[x][i];if(!y||h[y]<=h[x])continue;dfs(y);}add(bg[x],-1);
}

代码

版本一

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1using namespace std;typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 3e5+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);vector<int>v[maxn];
int id[maxn];
struct AC{//局部变量没有默认0!int trie[maxn][26];int num[maxn];//单词出现次数int fail[maxn],fa[maxn];int vis[maxn];//ask函数用到int tot,rt;int ntot;//多测可写个initvoid init(){tot=0;mem(vis,0);mem(trie,0);rt=0;ntot=0;}void add(char c){if(c=='P'){num[rt]++;id[++ntot]=rt;return;}if(c=='B'){rt=fa[rt];return;}int x = c-'a';if(!trie[rt][x]){trie[rt][x]=++tot;fa[tot]=rt;}//fa[trie[rt][x]]=rt;rt=trie[rt][x];}void build(){queue<int>q;for(int i = 0; i < 26; i++){if(trie[0][i]){//fail[trie[0][i]]=0;//v[0].pb(trie[0][i]);q.push(trie[0][i]);}}while(!q.empty()){int now = q.front();q.pop();for(int i = 0; i < 26; i++){让这个节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个相同节点)if(trie[now][i]){fail[trie[now][i]]=trie[fail[now]][i];//v[trie[fail[now]][i]].pb(trie[now][i]);q.push(trie[now][i]);}else trie[now][i]=trie[fail[now]][i];//否则就让当前节点的这个子节点指向当前节点fail指针的这个子节点   }v[fail[now]].pb(now);}}}ac;
char a[maxn];
int bg[maxn],ed[maxn];
int S[maxn],tot;
void gao(int x){S[++tot]=x;bg[x]=tot;for(int i = 0; i < (int)v[x].size(); i++){int y =v[x][i];gao(y);}//S[++tot]=x;ed[x]=tot;
}
int tree[maxn];
int lowbit(int x){return x&-x;}
void add(int x, int c){for(int i = x; i <= tot; i+=lowbit(i)){tree[i]+=c;}
}
int sum(int x){int ans =0;for(int i = x; i; i-=lowbit(i))ans+=tree[i];return ans;
}
vector<PI>Q[maxn];
int ans[maxn];
/*
void dfs(int x){//printf("%d\n",x);add(bg[x],1);for(int i = 0; i < (int)Q[x].size(); i++){int y = Q[x][i].fst;ans[Q[x][i].sc]=sum(ed[y])-sum(bg[y]-1);}for(int i = 0; i < 26; i++){int y = ac.trie[x][i];if(!y||(y==ac.trie[ac.fail[x]][i]))continue;dfs(y);}add(bg[x],-1);
}*/
void sv(){int now = 0;int n = strlen(a+1);int world=0;for(int i = 1; i <= n; i++){if(a[i]=='B'){add(bg[now],-1);now=ac.fa[now];continue;}else if(a[i]=='P'){world++;for(int j = 0; j < (int)Q[now].size(); j++){int x = Q[now][j].fst;int y = Q[now][j]. sc;ans[y]=sum(ed[x])-sum(bg[x]-1);}continue;}else{int x=a[i]-'a';now=ac.trie[now][x];add(bg[now],1);}}
}
int main(){ac.init();tot=0;scanf("%s", a+1);int n = strlen(a+1);for(int i = 1; i <= n; i++){ac.add(a[i]);}ac.build();int m;scanf("%d", &m);for(int i = 1; i <= m; i++){int x,y;scanf("%d %d", &x, &y);x=id[x];y=id[y];Q[y].pb(make_pair(x,i));}gao(0);//dfs(0);sv();for(int i = 1; i <= m; i++){printf("%d\n",ans[i]);}return 0;
}
/*
aPaPBbP
3
1 2
1 3
2 3a
aa
aa*/

版本二

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1using namespace std;typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 3e5+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);vector<int>v[maxn];
int id[maxn];
int h[maxn];
struct AC{//局部变量没有默认0!int trie[maxn][26];int num[maxn];//单词出现次数int fail[maxn],fa[maxn];int vis[maxn];//ask函数用到int tot,rt;int ntot;int H;//多测可写个initvoid init(){tot=0;mem(vis,0);mem(trie,0);rt=0;ntot=0;H=0;}void add(char c){if(c=='P'){num[rt]++;id[++ntot]=rt;return;}if(c=='B'){rt=fa[rt];H--;return;}int x = c-'a';if(!trie[rt][x]){trie[rt][x]=++tot;fa[tot]=rt;}//fa[trie[rt][x]]=rt;rt=trie[rt][x];h[rt]=++H;}void build(){queue<int>q;for(int i = 0; i < 26; i++){if(trie[0][i]){fail[trie[0][i]]=0;//v[0].pb(trie[0][i]);q.push(trie[0][i]);}}while(!q.empty()){int now = q.front();q.pop();for(int i = 0; i < 26; i++){让这个节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个相同节点)if(trie[now][i]){fail[trie[now][i]]=trie[fail[now]][i];//v[trie[fail[now]][i]].pb(trie[now][i]);q.push(trie[now][i]);}else trie[now][i]=trie[fail[now]][i];//否则就让当前节点的这个子节点指向当前节点fail指针的这个子节点   }v[fail[now]].pb(now);}}}ac;
char a[maxn];
int bg[maxn],ed[maxn];
int S[maxn],tot;
void gao(int x){S[++tot]=x;bg[x]=tot;for(int i = 0; i < (int)v[x].size(); i++){int y =v[x][i];gao(y);}//S[++tot]=x;ed[x]=tot;
}
int tree[maxn];
int lowbit(int x){return x&-x;}
void add(int x, int c){for(int i = x; i <= tot; i+=lowbit(i)){tree[i]+=c;}
}
int sum(int x){int ans =0;for(int i = x; i; i-=lowbit(i))ans+=tree[i];return ans;
}
vector<PI>Q[maxn];
int ans[maxn];void dfs(int x){//printf("==%d\n",x);add(bg[x],1);for(int i = 0; i < (int)Q[x].size(); i++){int y = Q[x][i].fst;ans[Q[x][i].sc]=sum(ed[y])-sum(bg[y]-1);}for(int i = 0; i < 26; i++){int y = ac.trie[x][i];if(!y||h[y]<=h[x])continue;dfs(y);}add(bg[x],-1);
}
void sv(){int now = 0;int n = strlen(a+1);int world=0;for(int i = 1; i <= n; i++){if(a[i]=='B'){add(bg[now],-1);now=ac.fa[now];continue;}else if(a[i]=='P'){world++;for(int j = 0; j < (int)Q[now].size(); j++){int x = Q[now][j].fst;int y = Q[now][j]. sc;ans[y]=sum(ed[x])-sum(bg[x]-1);}continue;}else{int x=a[i]-'a';now=ac.trie[now][x];add(bg[now],1);}}
}
int main(){ac.init();tot=0;scanf("%s", a+1);int n = strlen(a+1);for(int i = 1; i <= n; i++){ac.add(a[i]);}ac.build();int m;scanf("%d", &m);for(int i = 1; i <= m; i++){int x,y;scanf("%d %d", &x, &y);x=id[x];y=id[y];Q[y].pb(make_pair(x,i));}gao(0);dfs(0);//sv();for(int i = 1; i <= m; i++){printf("%d\n",ans[i]);}return 0;
}
/*
asPdPasPddPhBdPhPnaPasP
8
1 5
2 6
3 8
4 3
7 7
2 5
6 8
1 8a
aa
aa*/

转载于:https://www.cnblogs.com/wrjlinkkkkkk/p/11597485.html

BZOJ 2434 阿狸的打字机(ac自动机+dfs序+树状数组)相关推荐

  1. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

    [BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...

  2. 【bzoj2434】[Noi2011]阿狸的打字机 AC自动机+Dfs序+树状数组

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

  3. CF-547E(Mike and Friends)后缀数组+线段树 AC自动机+DFS序+树状数组

    题目链接 题意 NNN个串,每次询问区间[L,R][L,R][L,R]中有多少子串SiS_iSi​ 思路 把NNN个串合成一个长字符串,对这个长字符串求后缀数组,包含SiS_iSi​的子串的heigh ...

  4. P2414 NOI2011阿狸的打字机 [AC自动机,dfs序]

    阿狸的打字机 题解 题目中给出的字符串就是构建TrieTrieTrie树的顺序.我们将字符串依次读入,每读入一个小写字符就相当于在TrieTrieTrie树当前节点下插入一个小写字符,读入BBB时,就 ...

  5. bzoj 2434 [Noi2011]阿狸的打字机(AC自动机+fail树+dfs序+树状数组)

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 3521  Solved: 1913 [Submit][S ...

  6. BZOJ 1103: [POI2007]大都市meg [DFS序 树状数组]

    1103: [POI2007]大都市meg Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 2221  Solved: 1179 [Submit][S ...

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

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

  8. BZOJ 2434 NOI2011阿狸的打字机 AC自动机+树状数组

    如果你还没学AC自动机,请看这篇博客 Problem bzoj通道 洛谷通道 Solution 简单的说来,其实就是要快速求一个字符串在另一个字符串中出现了多少次.考虑构造AC自动机. 首先可以想到很 ...

  9. BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 我写的是离线做法,不知道有没有在线做法. 转化一波题意,\(x\)在AC ...

  10. 【bzoj2434】阿狸的打字机 AC自动机+树状数组

    AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=2434 [题解] 这是一道很神的题. 先建一个AC自动机,这里需要维护一下父结点,以便删除时 ...

最新文章

  1. linux监控平台搭建-内存
  2. 函数调用oracle,oracle 函数调用
  3. 如何用手机打开dcm格式图片_手机也能当扫描仪用?如何用手机扫描图片?
  4. 「产品规划」的那些事儿
  5. 北斗导航 | 精密单点定位软件之rtklib的静态定位测试(RTKlib)
  6. C语言入门题-计算到任意日期的总天数
  7. 200827C阶段一_C++基础
  8. vmware创建虚拟机不识别网卡
  9. 第一个Python程序——博客自动访问脚本
  10. python编程入门 pdf-Python编程从入门到精通.pdf
  11. Scikit-learn快速入门教程和实例(一)(二)
  12. elasticsearch安装使用
  13. 安装chrome插件:FireShot
  14. R语言编程环境的安装和运行
  15. 淘宝店如何加入全屏轮播图片
  16. 摄影测量中的什么是光流场_摄影中的“停止”是什么?
  17. 解析今日头条as,cp,_signiture参数---as,cp
  18. 常系数非齐次微分方程特解及其通解求解
  19. 电缆的差分特性阻抗(120欧姆)及插入损耗的测量方法
  20. 【完整的WebGIS教程】7.1 ArcGIS API for JS行政区划导航(上)

热门文章

  1. QT_TableWidget插入checkbox
  2. Linux内核开发_将Linux内核打包成img文件
  3. 深度理解“CPU内部寻址方式”
  4. Android热修复技术初探(三):动态加载外部资源
  5. ctags 的最简单使用
  6. 【python】Django设置SESSION超时时间没有生效?
  7. ie6下 jsonp无响应的问题
  8. MFC 文档 视图 框架窗口间的关系 和消息传送规律
  9. Linux 性能测试与分析-转
  10. C# Explicit 和 Implicit