题目大意:有一种打字机上有28个字母,分别是26个小写字母和BP,其中B代表退格,P代表换行,每一行就是一个字符串。现在给这些字符串标号,并询问x串在y串中出现过几次。
思路:这算是NOI史上最难的字符串的题了吧(动物园)。
首先按照题意不难建一个AC自动机出来,按照正常的思路,对于每一个询问都需要在AC自动机上暴力的查找。但这样时间会十分好看。
于是我们想,fail指针构成的一定是一棵树,将这颗树的DFS序搞出来的话会有非常好的性质--串中存在某个字串的一定在这个字串的子树中,也就是对应DFS序的一段区间里。这样我们吧所有询问离线,对整个trie树进行一次深搜,用fenwick来维护DFS序中的情况,顺便处理出来答案。
CODE:
#include <queue>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 100010
using namespace std;
#define P(a) ((a) - 'a')
struct Trie{
Trie *son[26],*fail;
int end;
Trie() {
memset(son,NULL,sizeof(son));
fail = NULL;
}
}mempool[MAX],*C = mempool + 1,*root = C++;
int asks;
int fenwick[MAX];
int head[MAX],total;
int next[MAX],aim[MAX];
int pos[MAX],p[MAX];
pair<int,int> range[MAX];
vector<pair<int,int> > G[MAX];
int ans[MAX];
inline void Add(int x,int y)
{
next[++total] = head[x];
aim[total] = y;
head[x] = total;
}
void BuildTrie()
{
static Trie *stack[MAX],*now = root;
int top = 0,cnt = 0;
char c;
stack[++top] = root;
while(c = getchar(),isalpha(c)) {
if(c == 'P') {
now->end = ++cnt;
p[now - mempool] = cnt;
}
else if(c == 'B')
now = stack[top--];
else {
stack[++top] = now;
if(now->son[P(c)] == NULL)
now->son[P(c)] = C++;
now = now->son[P(c)];
}
}
}
void BuildACAutomation()
{
static queue<Trie *> q;
while(!q.empty()) q.pop();
q.push(root);
while(!q.empty()) {
Trie *now = q.front(); q.pop();
for(int i = 0; i < 26; ++i) {
if(now->son[i] == NULL) continue;
if(now == root) {
now->son[i]->fail = root;
Add(root - mempool,now->son[i] - mempool);
}
else {
Trie *temp = now->fail;
while(temp != root && temp->son[i] == NULL) temp = temp->fail;
if(temp->son[i] != NULL) temp = temp->son[i];
now->son[i]->fail = temp;
Add(temp - mempool,now->son[i] - mempool);
}
q.push(now->son[i]);
}
}
}
void Pre(int x)
{
static int k = 0;
pos[x] = ++k;
if(p[x]) range[p[x]].first = k;
for(int i = head[x]; i; i = next[i])
Pre(aim[i]);
if(p[x]) range[p[x]].second = k;
}
inline void Fix(int x,int c)
{
for(; x < MAX; x += x&-x)
fenwick[x] += c;
}
inline int GetSum(int x)
{
int re = 0;
for(; x; x -= x&-x)
re +=fenwick[x];
return re;
}
void DFS(int x)
{
Trie *now = &mempool[x];
if(pos[x]) Fix(pos[x],1);
for(vector<pair<int,int> >::iterator it = G[p[x]].begin(); it != G[p[x]].end(); ++it) {
pair<int,int> now = *it;
ans[now.second] = GetSum(range[now.first].second) - GetSum(range[now.first].first - 1);
}
for(int i = 0; i < 26; ++i)
if(now->son[i] != NULL)
DFS(now->son[i] - mempool);
if(pos[x]) Fix(pos[x],-1);
}
int main()
{
BuildTrie();
BuildACAutomation();
cin >> asks;
for(int x,y,i = 1; i <= asks; ++i) {
scanf("%d%d",&x,&y);
G[y].push_back(make_pair(x,i));
}
Pre(1);
DFS(1);
for(int i = 1; i <= asks; ++i)
printf("%d\n",ans[i]);
return 0;
}
?BZOJ 2434 NOI 2011 阿狸的打字机 AC自动机构造fail树
原文:http://blog.csdn.net/jiangyuze831/article/details/41846483