Searching the String - ZOJ 3228(ac自动机)

时间:2023-03-09 19:08:59
Searching the String - ZOJ 3228(ac自动机)
题目大意:首先给你一下母串,长度不超过10^5,然后有 N(10^5) 次查询,每次查询有两种命令,0或者1,然后加一个子串,询问母串里面有多少个子串,0表示可以重复,1表示不可以重复。
 
分析:发现查询的次数是比较多的,然后可以利用查询的串建立一个trie,然后用母串跑一遍就行了,不过有两种操作比较麻烦一些,不过我们可以保存查询时每个节点的查询结果,然后每个串都对应一个节点,最后输出查询结果即可,这样也可以规避掉重复串的问题。
 
代码如下:
===============================================================================================================
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std; const int MAXN = 6e5+;
const int MaxSon = ; char MumStr[MAXN];
int Num[MAXN], op[MAXN]; struct Ac_Trie
{
int next[MAXN][MaxSon];
int Fail[MAXN];
///End保存每个单词匹配成功后最后面的位置
///如果这个节点是一个单词,Len保存这个单词的长度
int End[MAXN], Len[MAXN];
int ans[MAXN][];///保存两种状态的答案
int root, cnt; int newnode()
{
for(int i=; i<MaxSon; i++)
next[cnt][i] = -;
Len[cnt] = Fail[cnt] = false;
End[cnt] = -;
ans[cnt][] = ans[cnt][] = ; return cnt++;
}
void InIt()
{
cnt = ;
root = newnode();
}
int Insert(char s[])
{///返回这个字符串对应的节点编号
int i, now = root; for(i=; s[i]; i++)
{
int k = s[i] - 'a'; if(next[now][k] == -)
next[now][k] = newnode();
now = next[now][k];
} Len[now] = i; return now;
}
void GetFail()
{
queue<int> Q;
int i, now = root; for(i=; i<MaxSon; i++)
{
if(next[now][i] == -)
next[now][i] = root;
else
{
Fail[next[now][i]] = root;
Q.push(next[now][i]);
}
} while(Q.size())
{
now = Q.front();
Q.pop(); for(i=; i<MaxSon; i++)
{
if(next[now][i] == -)
next[now][i] = next[Fail[now]][i];
else
{
Fail[next[now][i]] = next[Fail[now]][i];
Q.push(next[now][i]);
}
}
}
}
void Query(char MumStr[])
{
int i, now = root, temp; for(i=; MumStr[i]; i++)
{
int k = MumStr[i] - 'a'; now = next[now][k]; if(!now)continue; temp = now; while(temp != root)
{
if(Len[temp])
ans[temp][]++;
if(Len[temp] && (i-End[temp] >= Len[temp]) )
ans[temp][]++, End[temp] = i; temp = Fail[temp];
}
}
}
};
Ac_Trie ac;
int main()
{
int i, M, t=; while(scanf("%s", MumStr) != EOF)
{
char s[];
ac.InIt(); scanf("%d", &M); for(i=; i<=M; i++)
{
scanf("%d%s", &op[i], s);
Num[i] = ac.Insert(s);
} ac.GetFail();
ac.Query(MumStr); printf("Case %d\n", t++);
for(i=; i<=M; i++)
printf("%d\n", ac.ans[Num[i]][op[i]]);
printf("\n");
} return ;
}