zoukankan      html  css  js  c++  java
  • HDU4787 GRE Words Revenge【AC自动机 分块】

    HDU4787 GRE Words Revenge

    题意:

    (N)次操作,每次记录一个(01)串或者查询一个(01)串能匹配多少个记录的串,强制在线

    题解:

    在线的AC自动机,利用分块来降低复杂度,建两个AC自动机,一个大的一个小的,每次往小的里面加字符串,当小的自动机的大小大于一定值之后把小的自动机和大的自动机合并,然后清空小的自动机
    每次询问把小的自动机和大的自动机的答案加在一起即可

    TIPS:不能把(fail)边直接作为子节点来建图,因为之后还要加字符串进去

    //#pragma GCC optimize("O3")
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    const int MAXN = 5e6+7;
    class ACautomaton{
    private:
        int fail[MAXN],ch[MAXN][2],tot,last[MAXN],cnt[MAXN];
        queue<int> que;
        bool updated;
        void buildfail(){
            for(int i = 0; i < 2; i++){
                if(!ch[0][i]) continue;
                que.push(ch[0][i]);
                fail[ch[0][i]] = last[ch[0][i]] = 0;
            }
            while(!que.empty()){
                int u = que.front();
                que.pop();
                for(int c = 0; c < 2; c++){
                    int v = ch[u][c];
                    if(!v) continue;
                    int p = fail[u];
                    while(p and !ch[p][c]) p = fail[p];
                    fail[v] = ch[p][c];
                    last[v] = cnt[fail[v]]?fail[v]:last[fail[v]];
                    que.push(v);
                }
            }
        }
    public:
        void clear(){
            for(int i = 0; i <= tot; i++){
                ch[i][0] = ch[i][1] = 0;
                cnt[i] = 0;
            }
            tot = 0; updated = false;
        }
        void insert(char *s){
            updated = true;
            int now = 0;
            for(int i = 0; s[i]; i++){
                int c = s[i] - '0';
                if(!ch[now][c]) ch[now][c] = ++tot;
                now = ch[now][c];
            }
            cnt[now] = 1;
        }
        int mt(int u){
            int ret = 0;
            while(u){
                ret += cnt[u];
                u = last[u];
            }
            return ret;
        }
        int match(char *s){
            if(updated) buildfail();
            updated = false;
            int ret = 0, now = 0;
            for(int i = 0; s[i]; i++){
                int c = s[i] - '0';
                while(now and !ch[now][c]) now = fail[now];
                now = ch[now][c];
                ret += mt(now);
            }
            return ret;
        }
        int size(){ return tot; }
        void merge(ACautomaton &rhs, int u, int v){
            updated = true;
            for(int c = 0; c < 2; c++){
                if(!rhs.ch[v][c]) continue;
                if(!ch[u][c]) ch[u][c] = ++tot;
                merge(rhs,ch[u][c],rhs.ch[v][c]);
            }
            cnt[u] |= rhs.cnt[v];
        }
    }aho[2];
    char s[MAXN],t[MAXN];
    void solve(int kase){
        printf("Case #%d:
    ",kase);
        aho[0].clear(); aho[1].clear();
        int lastres = 0, q;
        scanf("%d",&q);
        int up = sqrt(MAXN);
        while(q--){
            scanf("%s",s);
            int len = strlen(s+1);
            int shift = lastres % len;
            t[len] = '';
            for(int i = 0; i < len; i++) t[i] = s[(i+shift)%len+1];
            if(s[0]=='?') printf("%d
    ",lastres=aho[0].match(t)+aho[1].match(t));
            else{
                aho[1].insert(t);
                if(aho[1].size()>up){
                    aho[0].merge(aho[1],0,0);
                    aho[1].clear();
                }
            }
        }
    }
    int main(){
        int T; scanf("%d",&T);
        for(int kase = 1; kase <= T; kase++) solve(kase);
        return 0;
    }
    
  • 相关阅读:
    Trie树
    递归函数两种方式的区别
    揭开HTTPS的神秘面纱
    补码到底是个什么东西
    浮点数的运算精度丢失
    PHP的stdClass
    2019-10-24
    MySQL存储引擎
    代码整洁之道小结
    NFS4 挂载同主机多个目录
  • 原文地址:https://www.cnblogs.com/kikokiko/p/12883857.html
Copyright © 2011-2022 走看看