• bzoj 2434 AC自动机 + fail指针建树 + 树状数组


    思路:我们先跟着它给定的字符串走把字典树建出来,求出fail指针,我们考虑两个字符串 A和B,

    如果想要求B中有多少A的子串,转换一下就是有多少个B的前缀的后缀包含A,这个在AC自动机

    的状态图中很容易表示,就是字符串B所占的结点中 有多少个结点顺着fail能到达A的尾结点,

    并且fail构建出来的图是一棵树,转换成A的尾结点的子树中有多少个B的节点,用dfs序构建树状

    数组能很容易完成,又因为有m组询问,我们把询问离线排序,就能解决问题啦。

    #include<bits/stdc++.h>
    #define LL long long
    #define ll long long
    #define fi first
    #define se second
    #define mk make_pair
    #define PII pair<int, int>
    #define y1 skldjfskldjg
    #define y2 skldfjsklejg
    
    using namespace std;
    
    const int N = 2e5 + 7;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1000000007;
    
    int n, m, pos, ans[N], t[N];
    char s[N];
    
    struct Qus {
        int x, y, id;
        bool operator < (const Qus &rhs) const {
            return y < rhs.y;
        }
    } qus[N];
    
    struct BIT {
        int a[N];
        void modify(int x, int v) {
            for(int i = x; i < N; i += i & -i)
                a[i] += v;
        }
        int sum(int x) {
            int ans = 0;
            for(int i = x; i; i -= i & -i)
                ans += a[i];
            return ans;
        }
    } bit;
    
    struct Ac {
        int ch[N][26], val[N], dp[N], f[N], L[N], R[N], tot, sz, cnt, all;
        bool vis[N];
        vector<PII> vec[N];
        vector<int> edge[N];
    
        Ac(int sz) {this->sz = sz;}
        void init() {tot = 0;}
        int newNode() {
            tot++; f[tot] = 0; val[tot] = 0;
            memset(ch[tot], 0, sizeof(ch[tot]));
            return tot;
        }
        inline int idx(char c) {return c - 'a';}
        void addStr(char *s) {
            stack<int> stk;
            int u = 0;
            stk.push(0);
            for(int i = 0; s[i]; i++) {
                if(s[i] == 'P') {
                    cnt++; val[u]++; t[cnt] = u;
                    while(pos <= n && qus[pos].y <= cnt)
                        vec[u].push_back(mk(qus[pos].x, qus[pos].id)), pos++;
                } else if(s[i] == 'B') {
                    if(stk.size() > 1) {
                        stk.pop();
                        u = stk.top();
                    }
                } else {
                    int c = idx(s[i]);
                    if(!ch[u][c]) ch[u][c] = newNode();
                    u = ch[u][c];
                    stk.push(u);
                }
            }
        }
        
        void build() {
            queue<int> que;
            for(int c = 0; c < sz; c++) {
                int v = ch[0][c];
                if(!v) ch[0][c] = 0;
                else f[v] = 0, que.push(v);
            }
            while(!que.empty()) {
                int u = que.front(); que.pop();
                val[u] |= val[f[u]];
                for(int c = 0; c < sz; c++) {
                    int v = ch[u][c];
                    if(!v) ch[u][c] = ch[f[u]][c];
                    else f[v] = ch[f[u]][c], que.push(v);
                }
            }
        }
    
        void dfs(int u) {
            L[u] = ++all;
            for(int i = 0; i < edge[u].size(); i++) {
                int v = edge[u][i];
                dfs(v);
            }
            R[u] = all;
        }
    
        void solve(char *s) {
            for(int i = 1; i <= tot; i++)
                edge[f[i]].push_back(i);
    
            dfs(0);
    
            stack<int> stk;
            int u = 0;
            stk.push(0);
            bit.modify(L[0], 1);
            for(int i = 0; s[i]; i++) {
                if(s[i] == 'P') {
                    if(vis[u]) continue;
                    vis[u] = true;
    
                    for(int i = 0; i < vec[u].size(); i++) {
                        int x = t[vec[u][i].fi], id = vec[u][i].se;
                        ans[id] = bit.sum(R[x]) - bit.sum(L[x] - 1);
                    }
                } else if(s[i] == 'B') {
                    if(stk.size() > 1) {
                        bit.modify(L[u], -1);
                        stk.pop();
                        u = stk.top();
                    }
                } else {
                    int c = idx(s[i]);
                    u = ch[u][c];
                    stk.push(u);
                    bit.modify(L[u], 1);
                }
            }
            for(int i = 1; i <= n; i++) printf("%d
    ", ans[i]);
        }
    } ac(26);
    
    int main() {
        ac.init(); pos = 1;
        scanf("%s%d", s, &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &qus[i].x, &qus[i].y);
            qus[i].id = i;
        }
        sort(qus + 1, qus + 1 + n);
        ac.addStr(s);
        ac.build();
        ac.solve(s);
        return 0;
    }
    
    
    /*
    */
  • 相关阅读:
    file_get_contents高級用法
    php缓存技术常用函数
    php爬虫的两种思路
    jQuery判断文本框是否为空
    Asp.net 实现图片缩放 无水印(方法二)
    C# winform关于DataGridView的一些操作
    PHP判断访问者手机移动端还是PC端的函数
    本地图片显示在网页
    如何安装 Composer
    国内开源镜像站
  • 原文地址:https://www.cnblogs.com/CJLHY/p/9493530.html
Copyright © 2020-2023  润新知