题目大意:首先给你一下母串,长度不超过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; }
时间: 2024-10-07 20:39:35