NOIP模拟 string - ac自动机

题目大意:

给n个字符串(100位以内),和一个长串s(100000位以内),求n个字符串在s中出现的次数。然后给出m次修改,每次修改s中的一个字符,对于每次修改,输出更新后的答案(修改会保存)。

题目分析:

没有修改就是ac自动机裸题。虽然带了修改,但发现匹配的字符串最多才100位,也就是说每次修改的pos位置的字符最多影响[pos-l,pos+l]这个区间的答案,于是便有了正解:每次修改前,将该区间的答案减掉,在加上修改后该区间的答案。

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<cmath>
using namespace std;

struct node{
    int trans[30], fail, cnt;
    inline void init(){
        memset(trans, 0, sizeof trans);
        fail = cnt = 0;
    }
}tr[1000005];
int tot = 0;

inline void insert(string &s){
    int pos = 0;
    for(int i = 0; i < s.length(); i++){
        if(!tr[pos].trans[s[i] - 'a' + 1]) tr[tr[pos].trans[s[i] - 'a' + 1] = ++tot].init();
        pos = tr[pos].trans[s[i] - 'a' + 1];
    }
    tr[pos].cnt++;
}

inline void build_fail(){
    queue<int> que;
    que.push(0);
    while(!que.empty()){
        int u = que.front(); que.pop();
        tr[u].cnt += tr[tr[u].fail].cnt;
        for(int i = 1; i <= 26; i++){
            if(tr[u].trans[i]){
                que.push(tr[u].trans[i]);
                if(u) tr[tr[u].trans[i]].fail = tr[tr[u].fail].trans[i];
            }
            else tr[u].trans[i] = tr[tr[u].fail].trans[i];
        }
    }
}

string t;
inline int ac(int l, int r){
    int ans = 0, pos = 0;
    for(int i = l; i <= r; i++){
        pos = tr[pos].trans[t[i] - 'a' + 1];
        ans += tr[pos].cnt;
    }
    return ans;
}

int maxl;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);
    int n, q; cin >> n >> q;
    for(int i = 1; i <= n; i++){
        string s;
        cin >> s;
        insert(s); int len = s.length();
        maxl = max(maxl, len);
    }
    build_fail();
    cin >> t;
    int ans; 
    int len = t.length();
    cout << (ans = ac(0, len - 1)) << endl;
    for(int i = 1; i <= q; i++){
        int pos; char c; cin >> pos >> c; pos--;
       
        ans -= ac(max(0, pos - maxl), min(len - 1, pos + maxl));
        t[pos] = c;
        ans += ac(max(0, pos - maxl), min(len - 1, pos + maxl));
        cout << ans << endl;
    }
    return 0;
}

posted @ 2017-10-17 19:57  CzYoL  阅读(169)  评论(0编辑  收藏  举报