题意:中文题我就不多说什么了
以前也做过几个AC自动机+数据结构优化的题目,都是建好fail树然后就跟ac自动机无关了,所以这种题目都必须深刻理解AC自动机的原理以及fail树是怎么回事。
第一步:先读入字符串,建好AC自动机,我在这里被坑了,,,根据题目的特殊性,可以O(n)插入到字典树里面
第二步:建成fail树,预处理dfs序。
第三步: 离线回答询问。
联想暴力的算法,遍历每一个单词,每到一个节点,就一直fail fail,如果出现x的尾节点,就+1,。但这样子太暴力了,我们可以想一下,一直fail fail的过程,不就像一直往父亲节点的方向走么,如果将fail指针指向的点当成父亲几点建出一棵树,判断x在y中出现了几次,不就是判断字典树中root->y的路径中有几个点存在于x所在尾节点的子树中么,动态统计一棵子树中有几个点,就需要用数据结构来维护了。具体做的时候可以碰到一个Y的尾节点就处理所有的 对应的x的询问。
虽然调了好久,但其实是水题啊!!
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
const int M = 100010;
const int CD = 26;
struct BIT{
int c[M];
void init() {
memset(c,0,sizeof(c));
}
void update(int x,int d){
for(;x<M;x+=x&-x) c[x] += d;
}
int sum(int x) {
int ans = 0;
for(;x>0;x-=x&-x) ans += c[x];
return ans;
}
}bit;
struct Fail_tree {
vector<int> Eg[M];
int L[M] , R[M] ;
int tfn ;
void add(int a,int b)
{
Eg[a].push_back(b);
}
void dfs(int a)
{
L[a] = ++tfn;
for(vector<int>::iterator it = Eg[a].begin();it!=Eg[a].end();it++)
dfs(*it);
R[a] = tfn;
}
}FT;
bool vis[M];
struct ACM {
void init()
{
words = 0;
fail[0] = 0; val[0] = 0;
memset(ch[0],0,sizeof(ch[0]));
sz = 1;
for(int i = 0; i < 26; i++) ID[i+'a'] = i;
}
void Insert(char *s)
{
int p=0;
for(;*s;s++){
if(*s == 'P') {
++words;
hash[words] = p;
name[p].push_back(words);
} else if(*s == 'B') {
p = fa[p];
} else {
int c = ID[*s];
if(!ch[p][c]){
memset(ch[sz],0,sizeof(ch[sz]));
val[sz]=0;
fa[sz] = p;
ch[p][c]=sz++;
}
p=ch[p][c];
}
}
}
void Construct()
{
int *s=Q,*e=Q;
for(int i=0;i<CD;i++){
if(ch[0][i]){
fail[ch[0][i]] = 0;
*e++ = ch[0][i];
}
}
while(s!=e){
int u = *s++;
for(int i=0;i<CD;i++){
int &v = ch[u][i];
if(v){
*e++ = v;
fail[v]=ch[fail[u]][i];
} else {
v=ch[fail[u]][i];
}
}
}
}
void build()
{
init();
Insert(str);
Construct();
FT.tfn = 0;
for(int i = 1; i < sz; i++) FT.add(fail[i],i) ;
FT.dfs(0);
}
void solve()
{
build();
bit.init();
int p = 0;
for(int i = 0; str[i]; i++){
if(str[i] == 'P') {
if(vis[p]) continue;
vis[p] = true;
int tsz = name[p].size();
for(int j = 0; j < tsz ; j++) {
int y = name[p][j];
int ysz = edge[y].size();
for(int k = 0; k < ysz; k ++) {
int word = edge[y][k].first ;
int id = edge[y][k].second;
ans[id] = bit.sum(FT.R[hash[word]]) - bit.sum(FT.L[hash[word]] - 1) ;
}
}
} else if(str[i] == 'B') {
bit.update(FT.L[p],-1);
p = fa[p];
} else {
p = ch[p][ID[str[i]]] ;
bit.update(FT.L[p],1);
}
}
for(int i = 0; i < m; i++) printf("%d\n",ans[i]);
}
void input()
{
int x , y;
scanf("%s",str);
scanf("%d",&m);
for(int i = 0; i < m; i++) {
scanf("%d%d",&x,&y);
edge[y].push_back(make_pair(x,i));
}
}
vector<int> name[M];
int hash[M];
int ans[M];
vector<pair<int,int> > edge[M];
int words;
int tot;
char ss[M];
int m;
int ID[128];
int fail[M];
int sz;
int ch[M][CD];
int Q[M];
int val[M];
int fa[M];
char str[M];
}AC;
int main()
{
AC.input();
AC.solve();
return 0;
}