原題連接
php
每一個測試點,一開始給咱們n,m,k而後是一個長度爲n的字符串。
ios
以後m次操做,1 c是往字符串後面添加一個字符c,2是查詢字符串中出現k次以及以上的子串個數,m爲2e5
算法
首先能夠看出這是在線算法(離線其實也能夠),而後是查詢出現至少k次的子串,這樣咱們能夠直接聯繫到後綴自動機,與咱們本題的需求較爲契合
測試
咱們知道後綴自動機中,每一個節點表明的不一樣子串數量爲spa
而後若是某個節點在訪問以前就達到了k,則不須要繼續向上更新了,由於上面的節點也確定大於等於k,而且在以前就被記錄了
code
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N = 250000; int n, m, k, last = 0, co = 0; long long ans = 0; char ss[N + 5]; struct Sam { int fl; int len; int fail; int sn[26]; } sam[N * 2 + 5]; void inits(int o) { sam[o].fail = -1; sam[o].len = 0; sam[o].fl = 0; for (int i = 0; i < 26; ++i) { sam[o].sn[i] = 0; } } void update(int o) { while (o > 0 && sam[o].fl < k) { ++sam[o].fl; if (sam[o].fl >= k) { ans += sam[o].len - sam[sam[o].fail].len; } o = sam[o].fail; } } void add(char c) { int noww = ++co; inits(noww); sam[noww].len = sam[last].len + 1; int p = last; while (p != -1 && !sam[p].sn[c - 'a']) { sam[p].sn[c - 'a'] = noww; p = sam[p].fail; } if (p == -1) { sam[noww].fail = 0; } else { int q = sam[p].sn[c - 'a']; if (sam[q].len == sam[p].len + 1) { sam[noww].fail = q; } else { int cp = ++co; sam[cp] = sam[q]; sam[cp].len = sam[p].len + 1; // sam[cp].fl = 0; sam[q].fail = cp; sam[noww].fail = cp; while (p != -1 && sam[p].sn[c - 'a'] == q) { sam[p].sn[c - 'a'] = cp; p = sam[p].fail; } } } last = noww; update(noww); } int main() { while (scanf("%d%d%d", &n, &m, &k) == 3) { co = 0; last = 0; scanf("%s", ss); ans = 0; inits(0); for (int i = 0; ss[i]; ++i) { add(ss[i]); } for (int i = 1; i <= m; ++i) { int opt; scanf("%d", &opt); if (opt == 1) { char c[5]; scanf("%s", c); add(c[0]); } else { printf("%lld\n", ans); } } } return 0; }