您的位置:首页 > 其它

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

2015-08-26 15:57 337 查看
题目大意:首先给你一下母串,长度不超过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+7;
const int MaxSon = 26;

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][2];///保存两种状态的答案
int root, cnt;

int newnode()
{
for(int i=0; i<MaxSon; i++)
next[cnt][i] = -1;
Len[cnt] = Fail[cnt] = false;
End[cnt] = -10;
ans[cnt][0] = ans[cnt][1] = 0;

return cnt++;
}
void InIt()
{
cnt = 0;
root = newnode();
}
int Insert(char s[])
{///返回这个字符串对应的节点编号
int i, now = root;

for(i=0; s[i]; i++)
{
int k = s[i] - 'a';

if(next[now][k] == -1)
next[now][k] = newnode();
now = next[now][k];
}

Len[now] = i;

return now;
}
void GetFail()
{
queue<int> Q;
int i, now = root;

for(i=0; i<MaxSon; i++)
{
if(next[now][i] == -1)
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=0; i<MaxSon; i++)
{
if(next[now][i] == -1)
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=0; 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][0]++;
if(Len[temp] && (i-End[temp] >= Len[temp]) )
ans[temp][1]++, End[temp] = i;

temp = Fail[temp];
}
}
}
};
Ac_Trie ac;
int main()
{
int i, M, t=1;

while(scanf("%s", MumStr) != EOF)
{
char s[10];
ac.InIt();

scanf("%d", &M);

for(i=1; 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=1; i<=M; i++)
printf("%d\n", ac.ans[Num[i]][op[i]]);
printf("\n");
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: