bzoj 2434: 阿狸的打字机 fail树+离线树状数组

题目大意:

http://www.lydsy.com/JudgeOnline/problem.php?id=2434

题解:

首先我们可以发现这个打字的过程本身就是在Trie上滚来滚去的过程
所以我们可以直接根据这个建树
然后构建出fail树后我们考虑如何处理询问
对于任意一个询问(x,y)我们都可以统计从y到root的节点上有多少指向x的fail
但是这样肯定超时
所以反向考虑x的所有指向x的fail,和指向指向x的fail的fail... ...
我们把所有的fail反响建出一颗树来
这时候我们发现以x为根的子树即为所有直接或间接指向x的fail(反转前)
所以我们统计一下这可子树中有多少y即可
所以可以树套树解决
我们发现我们可以直接离线树状数组瞎搞
我们直接重复一遍打印的过程,把当前在凹槽中的字符对应的fail树的dfs序上+1
离线询问后直接查询即可

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
    x=0;char ch;bool flag = false;
    while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 100010;
int ch[maxn][26],nodecnt,fa[maxn];
int val[maxn];
char str[maxn];
struct Edge{
    int to,next;
}G[maxn];
int head[maxn],cnt;
void add(int u,int v){
    G[++cnt].to = v;
    G[cnt].next = head[u];
    head[u] = cnt;
}
int q[maxn],l,r,f[maxn];
inline void build(){
    f[0] = 0;l = 0;r = -1;
    int u = 0;
    for(int c=0;c<26;++c){
        if(ch[u][c]){
            f[ch[u][c]] = 0;
            q[++r] = ch[u][c];
        }
    }
    while(l <= r){
        u = q[l++];
        for(int c=0;c<26;++c){
            int v = ch[u][c];
            if(!v){
                ch[u][c] = ch[f[u]][c];
                continue;
            }q[++r] = v;
            int x = f[u];
            while(x && !ch[x][c]) x = f[x];
            f[v] = ch[x][c];
        }
    }
}
int ind[maxn],oud[maxn],dfs_clock = -1;
#define v G[i].to
inline void dfs(int u){
    ind[u] = ++ dfs_clock;
    for(int i = head[u];i;i=G[i].next) dfs(v);
    oud[u] = dfs_clock;
}
#undef v
struct Node{
    int x,y,id;
    bool friend operator < (const Node &a,const Node &b){
        return a.y < b.y;
    }
}a[maxn];
int anss[maxn];
int c[maxn],num;
#define lowbit(x) (x&-x)
inline void modify(int x,int y){
    for(;x<=dfs_clock + 10;x += lowbit(x)) c[x] += y;
}
inline int query(int x){
    int ret = 0;
    for(;x;x-=lowbit(x)) ret += c[x];
    return ret;
}
int mp[maxn];
int main(){
    scanf("%s",str);
    int n = strlen(str);
    int nw = 0;
    for(int i=0;i<n;++i){
        if(str[i] == 'P') val[nw] = ++num,mp[num] = nw;
        else if(str[i] == 'B') nw = fa[nw];
        else{
            int c = str[i] - 'a';
            if(ch[nw][c] == 0){
                ch[nw][c] = ++nodecnt;
                fa[nodecnt] = nw;
            }nw = ch[nw][c];
        }
    }build();
    for(int i=nodecnt;i>=1;--i) add(f[i],i);
    dfs(0);
    int m;read(m);
    for(int i=1;i<=m;++i){
        read(a[i].x);
        read(a[i].y);
        a[i].id = i;
    }sort(a+1,a+m+1);
    nw = 0;int p = 1,cnt_p = 0;
    for(int i=0;i<n;++i){
        if(str[i] == 'P'){
            ++ cnt_p;
            while(a[p].y == cnt_p){
                anss[a[p].id] = query(oud[mp[a[p].x]])-query(ind[mp[a[p].x]]-1);
                ++p;
            }
        }else if(str[i] == 'B'){
            modify(ind[nw],-1);
            nw = fa[nw];
        }else{
            int c = str[i] - 'a';
            nw = ch[nw][c];
            modify(ind[nw],1);
        }
    }
    for(int i=1;i<=m;++i) printf("%d\n",anss[i]);
    getchar();getchar();
    return 0;
}
posted @ 2017-03-03 06:32  Sky_miner  阅读(162)  评论(0编辑  收藏  举报