题目大意:给出一个字符串,支持在线在字符串后面加一个字符串,查询一个字符串在串中出现过几次。
思路:如果不想写正解的话,这个题就是后缀自动机的简单应用。正解其实是LCT+SAM,但是时间比暴力慢一倍。。。
暴力就很简单了,正序建立后缀自动机,每次查询的时候找到位置直接输出size的值。注意两点,一个是分裂节点的时候,size也要复制过去。查询的时候发现找不到要return 0;
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 4000010 using namespace std; struct Complex{ Complex* tranc[26],*father; int len,size; }mempool[MAX],*C = mempool,*last,*root,none,*nil = &none; Complex *NewComplex(int _) { C->len = _; C->size = 0; fill(C->tranc,C->tranc + 26,nil); C->father = nil; return C++; } void Initialize() { root = last = NewComplex(0); } inline void Add(int c) { Complex *np = NewComplex(last->len + 1),*p = last; for(; p != nil && p->tranc[c] == nil; p = p->father) p->tranc[c] = np; if(p == nil) np->father = root; else { Complex *q = p->tranc[c]; if(q->len == p->len + 1) np->father = q; else { Complex *nq = NewComplex(p->len + 1); memcpy(nq->tranc,q->tranc,sizeof(nq->tranc)); nq->father = q->father; np->father = q->father = nq; nq->size = q->size; for(; p != nil && p->tranc[c] == q; p = p->father) p->tranc[c] = nq; } } last = np; for(; np != root; np = np->father) ++np->size; } int asks; char s[MAX],opt[10]; inline void DecodeWithMask(int mask) { int length = strlen(s); for(int i = 0; i < length; ++i) { mask = (mask * 131 + i) % length; swap(s[i],s[mask]); } } inline int Ask() { Complex *now = root; int length = strlen(s); for(int i = 0; i < length; ++i) if(now->tranc[s[i] - 'A'] != nil) now = now->tranc[s[i] - 'A']; else return 0; return now->size; } int main() { Initialize(); scanf("%d%s",&asks,s); int length = strlen(s); for(int i = 0; i < length; ++i) Add(s[i] - 'A'); int mask = 0; for(int i = 1; i <= asks; ++i) { scanf("%s%s",opt,s); DecodeWithMask(mask); if(opt[0] == 'Q') { int last_ans = Ask(); printf("%d\n",last_ans); mask ^= last_ans; } else { length = strlen(s); for(int i = 0; i < length; ++i) Add(s[i] - 'A'); } } return 0; }
原文地址:http://blog.csdn.net/jiangyuze831/article/details/42876887