2434: [Noi2011]阿狸的打字机

ac自动机,bit,dfs序。

本文所有的stl都是因为自己懒得实现。

 

首先x在y里面出现,就意味y节点可以顺着fail回去。

反向建出一个fail数,然后搞出dfs序列。找出x对应的区间有多少个y。

再用离线操作,把每个y需要计算的x事先保存下来。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 100000 + 10;

char s[maxn];
int a[maxn][26];
int g[maxn],v[maxn],next[maxn],eid;
int pos[maxn],cnt;
int fa[maxn],fail[maxn],L[maxn],R[maxn],query[maxn][3];
int m,n,u,dfn,vid;
vector<int> Q[maxn];
queue<int> q;

struct BIT {
    int a[maxn<<1],n;
    
    int lowbit(int x) {
        return (x & -x);
    }
    
    void add(int x,int d) {
        //printf("c %d %d\n",x,d);
        for(;x<=n;x+=lowbit(x)) a[x]+=d;
        //printf("c");
    }
    
    int query(int x) {
        int res=0;
        for(;x;x-=lowbit(x)) res+=a[x];
        return res;    
    }
    
    void init(int _n) {
        n=_n;
    }
}bit;

void addedge(int a,int b) {
    v[eid]=b; next[eid]=g[a]; g[a]=eid++;
}

void dfs(int u) {
    L[u]=++dfn;
    for(int i=g[u];~i;i=next[i]) dfs(v[i]);
    R[u]=dfn;
}

void get_trie() {
    for(int i=0;i<26;i++) a[0][i]=1;
    
    int p=1,c;vid=1;
    for(int i=0;i<n;i++) {
        //printf("f[%d] = %d\n",i,p);
        if(s[i]=='P') pos[++cnt]=p;
        else if(s[i]=='B') p=fa[p];
        else {
            c=s[i]-'a';
            if(!a[p][c]) 
                a[p][c]=++vid,fa[vid]=p;
            p=a[p][c];
        }
        //printf("f[%d] = %d\n",i,p);
    }
}

void debug(int p) {
}

void get_fail() {
    fail[1]=0;
    q.push(1);
    
    while(!q.empty()) {
        u=q.front();q.pop();
        for(int k=0,p;k<26;k++)
        if(a[u][k]) {
            for(p=fail[u];p&&!a[p][k];p=fail[p]);
            fail[a[u][k]]=a[p][k];
            q.push(a[u][k]);
        }
    }
}

void get_tree() {
    for(int i=1;i<=vid;i++) addedge(fail[i],i);
    dfs(1);
}

void build() {
    memset(g,-1,sizeof(g));
    scanf("%s",s);n=strlen(s);
    
    get_trie();
    //debug(1);
    get_fail();
    get_tree(); 
    
    scanf("%d",&m);
    for(int i=1;i<=m;i++) {
        scanf("%d %d",&query[i][0],&query[i][1]);
        query[i][0]=pos[query[i][0]];
        query[i][1]=pos[query[i][1]];
        Q[query[i][1]].push_back(i);
    }
    
}

void solve() {
    bit.init(n<<1);
    int p=1;
    for(int i=0;i<n;i++) {
        //printf("s[i]=%c\n",s[i]);
        if(s[i]=='P') for(int j=0;j<Q[p].size();j++) 
            query[Q[p][j]][2]=bit.query(R[query[Q[p][j]][0]])-bit.query(L[query[Q[p][j]][0]]-1);
        else if(s[i]=='B') bit.add(L[p],-1),p=fa[p];
        else p=a[p][s[i]-'a'],bit.add(L[p],1);
        //printf(" %d\n",i);
    }
    
    for(int i=1;i<=m;i++) printf("%d\n",query[i][2]);
}

int main() {
    build();
    solve();
    
    return 0;
}
posted @ 2016-04-28 23:51  invoid  阅读(196)  评论(0编辑  收藏  举报