[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\n",ans[i]);
}
View Code

 

posted @ 2019-08-09 07:36  Vagari  阅读(148)  评论(0编辑  收藏  举报