• 洛谷p2414 [NOI2011]阿狸的打字机


    70分算法:我们把所有的串都添加到(AC)自动机,然后按照(y)排序,时间复杂度(O(n^2))
    我们考虑一些优化,
    我们求的其实就是有多少个(x)串是(y)串的前缀的后缀。
    其实就是(fail)指针的检索结构,
    然后我们可以建出(fail)树,
    然后转换一下询问。
    其实就是这个东西:
    把所有(y)串的节点的前缀打上标记,然后在所有(x)串节点的子树里统计个数,就是答案。
    维护个数和其实可以用(fail)树上求个(dfs)序然后使用线段树/树状数组完成。
    可是这样依然会超时。
    我们考虑继续优化。
    我们将y串使用原(trie)树上的(dfs)序。
    因为按照(dfs)遍历每个点最多只会进出一次,所以时间复杂度是(O(n log n))
    代码

    #include <bits/stdc++.h>
    
    const int maxn = 1e5 + 10;
    
    int n, m, i, j, k, tim1, tim2, cnty, tot, tmp;
    int ch[maxn][26], fail[maxn], fa[maxn], id[maxn];      
    std::vector<int> vec[maxn];  
    int dfn1[maxn], lca[maxn], rnk[maxn], c[maxn];
    int dfn2[maxn], tl[maxn], tr[maxn];   
    int hd[maxn], ver[maxn], nxt[maxn], ans[maxn], cnte;  
    char s[maxn];   
    struct query {
        int x, y, id;  
        query() { x = y = id = 0; }
        query(int _x,int _y,int _id) {
            x = _x;  y = _y;  id = _id; 
        }
        inline friend bool operator < (query a,query b) {
            return rnk[a.y] < rnk[b.y];   
        }
    } q[maxn]; 
    
    inline void add(int x,int y) {
        int n = tot + 1;
        while(x <= n)
            c[x] += y, x += x & -x;  
    }
    inline int ask(int x) {
        int res = 0;
        while(x)
            res += c[x], x -= x & -x;
        return res; 
    }
    
    inline void adde(int u,int v) {
        ver[++cnte] = v;  nxt[cnte] = hd[u];
        hd[u] = cnte;  return;  
    }
    
    inline void get_fail() {
        std::queue<int> q;  fail[0] = 0;
        for(int i = 0;i <= 25;i++) {
            if(ch[0][i]) {
                fail[ ch[0][i] ] = 0;
                q.push(ch[0][i]);
            }
        }
        while(!q.empty()) {
            int u = q.front();  q.pop();  
            for(int i = 0;i <= 25;i++) {
                if(ch[u][i]) {
                    fail[ ch[u][i] ] = ch[ fail[u] ][i];
                    q.push(ch[u][i]);
                } else {
                    ch[u][i] = ch[ fail[u] ][i];    
                }
            }      
        }
    }
    inline void ac_init() {
        get_fail();
        memset(hd,-1,sizeof(hd));       
        for(int i = 1;i <= tot;i++)
            adde(fail[i],i);
        return; 
    }
    
    void get_dfn1(int u) {
        int len = vec[u].size();
        for(int i = 0;i < len;i++) {
            int x = vec[u][i];
            dfn1[++tim1] = x;  
            rnk[x] = tim1;
            id[x] = u;   
            lca[tim1] = tmp;         
            tmp = u;    
        }
        for(int i = 0;i <= 25;i++) {
            int v = ch[u][i];     
            if(!v)
                continue;
            get_dfn1(v);  
            tmp = u;  
        }
    }
    void get_dfn2(int u) {
        dfn2[u] = ++tim2;  tl[u] = tim2;  
        for(int i = hd[u];~i;i = nxt[i]) {
            int v = ver[i];
            get_dfn2(v);   
        }  
        tr[u] = tim2;  
    }
    
    int main() {
        scanf("%s",s + 1);
        scanf("%d",&n);
        for(int i = 1;i <= n;i++)
            scanf("%d %d",&q[i].x,&q[i].y), q[i].id = i;
        int u = 0;
        for(int i = 1, l = strlen(s + 1);i <= l;i++) {
            if(s[i] == 'P') 
                vec[u].push_back(++cnty);
            else if(s[i] == 'B')
                u = fa[u];
            else {
                int c = s[i] - 'a';
                if(!ch[u][c])
                    ch[u][c] = ++tot;
                fa[ ch[u][c] ] = u;   
                u = ch[u][c];   
            }
        }
        get_dfn1(0);
        ac_init(); 
        get_dfn2(0);
        std::sort(q + 1,q + n + 1);
        u = 0;
        for(int i = 1, j = 1;i <= cnty;i++) {
            int x = dfn1[i], v = id[x];
            while(u != lca[i])
                add(dfn2[u],-1), u = fa[u];  
            while(v != u)
                add(dfn2[v],1), v = fa[v];
            u = id[x];  
            while(q[j].y == x) {
                int w = id[ q[j].x ];  
                ans[ q[j].id ] = ask(tr[w]) - ask(tl[w] - 1);     
                j++;
            }
        }
        for(int i = 1;i <= n;i++)
            printf("%d
    ",ans[i]);
        return 0;  
    }
    
    
  • 相关阅读:
    预习原码补码
    C语言I作业12-学期总结
    C语言I博客作业11
    C语言I博客作业10
    C语言I博客作业09
    C语言I博客作业08
    C语言I博客作业07
    C语言I博客作业06
    C语言I博客作业05
    C语言I作业004
  • 原文地址:https://www.cnblogs.com/Sai0511/p/11216767.html
Copyright © 2020-2023  润新知