zoukankan      html  css  js  c++  java
  • [AC自动机][树状数组]luogu P2414 阿狸的打字机

    https://www.luogu.org/problem/P2414

    分析

    容易发现询问串A属于串B多少次就是问访问串B时,跳完每个点的fail链,到达串A末尾的次数

    可以发现如果把fail树建出来,就相当于每到达一个点,就往fail树里面权值+1,离开时-1,当到达串B末尾时,询问串A末尾在fail树中子树的权值和

    用DFS序和树状数组可以轻松解决

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    #define lowbit(x) x&-x
    using namespace std;
    const int N=2e5+10;
    struct Graph {
        int v,nx;
    }g[N];
    int gcnt,list[N];
    int fail[N],t[N][26],cnt,v[N];
    struct Query {
        int x,y,id;
    }q[N];
    int m,len,tme,p;
    int l[N],r[N],end[N],ans[N],f[N];
    char c[N];
    
    void Add(int u,int v) {
        g[++gcnt]=(Graph){v,list[u]};list[u]=gcnt;
    }
    
    bool CMP(Query a,Query b) {
        return a.y<b.y;
    }
    
    void Insert() {
        int x=0,id=0;
        for (int i=1,n=strlen(c+1);i<=n;i++) {
            if (c[i]=='B') {
                x=f[x];
                continue;
            }
            if (c[i]=='P') {
                end[++id]=x;
                continue;
            }
            if (!t[x][c[i]-'a']) f[t[x][c[i]-'a']=++cnt]=x;
            x=t[x][c[i]-'a'];
        }
    }
    
    void Build() {
        queue<int> q;
        while (!q.empty()) q.pop();
        for (int i=0;i<26;i++) if (t[0][i]) q.push(t[0][i]),Add(0,t[0][i]);
        while (!q.empty()) {
            int u=q.front();q.pop();
            for (int i=0;i<26;i++)
                if (t[u][i]) {
                    int now=fail[u];
                    while (now&&!t[now][i]) now=fail[now];
                    fail[t[u][i]]=t[now][i];Add(t[now][i],t[u][i]);
                    q.push(t[u][i]);
                }
        }
    }
    
    void DFS(int u) {
        l[u]=++tme;
        for (int i=list[u];i;i=g[i].nx) DFS(g[i].v);
        r[u]=tme;
    }
    
    void Addc(int x,int c) {
        for (;x<=tme;x+=lowbit(x)) v[x]+=c;
    }
    
    int Sum(int x) {
        int ans=0;
        for (;x;x-=lowbit(x))ans+=v[x];
        return ans;
    }
    
    void Trie() {
        int x=0;
        for (int i=1,n=strlen(c+1);i<=n;i++) {
            if (c[i]=='B') {
                Addc(l[x],-1);x=f[x];
                continue;
            }
            if (c[i]=='P') {
                while (end[q[p].y]==x) ans[q[p].id]=Sum(r[end[q[p].x]])-Sum(l[end[q[p].x]]-1),p++;
                continue;
            }
            x=t[x][c[i]-'a'];Addc(l[x],1);
        }
    }
    
    int main() {
        scanf("%s",c+1);
        Insert();
        scanf("%d",&m);
        for (int i=1;i<=m;i++) scanf("%d%d",&q[i].x,&q[i].y),q[i].id=i;
        sort(q+1,q+m+1,CMP);
        Build();
        DFS(0);
        p=1;len=0;Trie();
        for (int i=1;i<=m;i++) printf("%d
    ",ans[i]);
    }
    View Code
  • 相关阅读:
    First Missing Positive
    Find Minimum in Rotated Sorted Array II
    switch两种写法对比
    常用的前端JavaScript方法封装
    如何保证缓存和数据库的一致性?
    14个前端小知识
    dataTable转换特定的类
    C# MD5 32大写位加密 UTF-8编码
    另一个 SqlParameterCollection 中已包含 SqlParameter
    C#实现数据回滚,A事件和B事件同时执行,其中任何一个事件执行失败,都会返回失败
  • 原文地址:https://www.cnblogs.com/mastervan/p/11324875.html
Copyright © 2011-2022 走看看