首先比较明显的是我们可以将字符串组建立ac自动机,那么对于询问s1字符串在s2字符串中出现的次数,就是在以s1结尾为根的fail tree中,子树有多少个节点是s2的节点,这样我们处理fail tree的dfs序,然后用BIT维护,但是如果只是在线处理询问的话会tle,因为每个询问需要将节点的每一位在BIT中都修改,那么我们就浪费了好多性质,因为对于好多字符串拥有较长的LCP,那么我们可以模拟建trie的过程在自动机上跑,每遇到一个添加的字符,就解决所有询问为某字符串在该字符串中出现的次数,这样就可以了。

/**************************************************************
    Problem: 2434
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:852 ms
    Memory:39128 kb
****************************************************************/
 
//By BLADEVIL
#include <cstdio>
#include <cstring>
#define maxn 200010
 
using namespace std;
 
struct node{
    int cnt,last,left,right;
    node *child[],*fail,*father;
    node(){
        cnt=last=left=right=;
        fail=father=NULL;
        memset(child,,sizeof child);
    }
}nodepool[maxn],*totnode,*root,*que[maxn],*adr[maxn],*other[maxn],*adrans[maxn];
char c[maxn];
int len,tot,l,sum;
int pre[maxn],bit[maxn];
int ll,preans[maxn],otherans[maxn],lastans[maxn],sizeans[maxn];
int ans[maxn];
 
void add(int x,int y){
    while (x<=sum){
        bit[x]+=y;
        x+=x&(-x);
    }
}
 
int ask(int x){
    int ans=;
    while (x){
        ans+=bit[x];
        x-=x&(-x);
    }
    return ans;
}
 
void connect(node *x,node *y){
    pre[++l]=x->last;
    x->last=l;
    other[l]=y;
    //printf("%d %d\n",x,y);
}
 
void connectans(int x,int y,int z){
    preans[++l]=lastans[x];
    lastans[x]=l;
    otherans[l]=y;
    sizeans[l]=z;
}
 
void build_trie(){
    totnode=nodepool; root=totnode++;
    scanf("%s",&c); len=strlen(c);
    node *t=root;
    for (int i=;i<len;i++){
        if (c[i]=='P') adrans[++tot]=t; else
        if (c[i]=='B') t=t->father; else {
            if (!t->child[c[i]-'a'])
                t->child[c[i]-'a']=totnode++,t->child[c[i]-'a']->father=t;
            t=t->child[c[i]-'a'];
            adr[i]=t;
        };
        //printf("%d ",t);
    }
    //printf("\n");
    //for (int i=0;i<len;i++) printf("%d ",adr[i]);
    //for (node *i=nodepool;i!=totnode;i++) printf("%d %d\n",i,i->father);
}
 
void build_ac(){
    int h=,t=;
    que[]=root; root->fail=root;
    for (int i=;i<;i++) if (!root->child[i]) root->child[i]=root;
    while (h<t){
        node *v=que[++h];
        for (int i=;i<;i++) if (v->child[i]&&v->child[i]!=root){
            que[++t]=v->child[i];
            node *u=v->fail;
            que[t]->fail=u->child[i]!=que[t]?u->child[i]:root;
        } else v->child[i]=v->fail->child[i];
    }
    //for (int i=1;i<=t;i++) printf("%d %d ",que[i],que[i]->fail); printf("\n");
    //for (int i=1;i<=tot;i++) printf("%d ",adr[i]); printf("\n");
}
 
void dfs(node *x,node *fa){
    //printf("%d %d %d\n",x,fa,sum);
    x->left=++sum;
    for (int p=x->last;p;p=pre[p]){
        if (other[p]==fa) continue;
        dfs(other[p],x);
    }
    x->right=sum;
}
 
/*void work(){
    for (node *i=nodepool;i!=totnode;i++) if (i!=root) connect(i->fail,i);
    dfs(root,NULL);
    //for (node *i=nodepool;i!=totnode;i++) printf("%d %d %d %d\n",i,i->left,i->right,i->father);
    int m;
    scanf("%d",&m);
    while (m--){
        int x,y;
        scanf("%d %d",&x,&y);
        for (node *i=adr[y];i!=root;i=i->father) add(i->left,1);//printf("%d ",i->left);
        //printf("%d %d",adr[x]->left,adr[x]->right);
        //printf("%d ",ask(adr[x]->right));
        printf("%d\n",ask(adr[x]->right)-ask(adr[x]->left-1));
        for (node *i=adr[y];i!=root;i=i->father) add(i->left,-1);
    }
}*/
 
void work(){
    for (node *i=nodepool;i!=totnode;i++) if (i!=root) connect(i->fail,i);
    dfs(root,NULL);
    int m;
    scanf("%d",&m);
    for (int i=;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        connectans(y,x,i);
    }
    int stack[maxn],tot=,ansy=;
    memset(stack,,sizeof stack);
    for (int i=;i<len;i++){
        if (c[i]=='P'){
            ansy++;
            for (int p=lastans[ansy];p;p=preans[p]){
                ans[sizeans[p]]=ask(adrans[otherans[p]]->right)-ask(adrans[otherans[p]]->left-);
            }
        } else
        if (c[i]=='B') {
            add(adr[stack[tot--]]->left,-);
        } else {
            stack[++tot]=i;
            add(adr[i]->left,);
        }
    }
    for (int i=;i<=m;i++) printf("%d\n",ans[i]);
}
 
int main(){
    build_trie();
    build_ac();
    work();
    return ;
}

bzoj 2434 fail tree+dfs序的更多相关文章

  1. POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和)

    POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和) 题意分析 卡卡屋前有一株苹果树,每年秋天,树上长了许多苹果.卡卡很喜欢苹果.树上有N个节点,卡卡给他们编号1到N,根 ...

  2. BZOJ 2905: 背单词 AC自动机+fail树+dfs序+线段树

    Description 给定一张包含N个单词的表,每个单词有个价值W.要求从中选出一个子序列使得其中的每个单词是后一个单词的子串,最大化子序列中W的和. Input 第一行一个整数TEST,表示数据组 ...

  3. bzoj2434 fail树 + dfs序 + 树状数组

    https://www.lydsy.com/JudgeOnline/problem.php?id=2434 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现, ...

  4. 【Codeforces163E】e-Government AC自动机fail树 + DFS序 + 树状数组

    E. e-Government time limit per test:1 second memory limit per test:256 megabytes input:standard inpu ...

  5. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

  6. NOI2011阿狸的打字机(fail树+DFS序)

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  7. poj 3321 Apple Tree dfs序+线段树

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K       Description There is an apple tree outsid ...

  8. [poj3321]Apple Tree(dfs序+树状数组)

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 26762   Accepted: 7947 Descr ...

  9. Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+树状数组

    C. Propagating tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/383/p ...

随机推荐

  1. python: error while loading shared libraries: libpython2.7.so.1.0: cannot open shared object file: No such file or directory

    #vi /etc/ld.so.conf.d/python2.7.conf   加入/usr/local/python27/lib   保存退出后执行 #ldconfig

  2. Mysql查询优化从入门到跑路(二)数据库查询优化技术总揽

    五大优化技术 1.查询重用 查询重用是指尽可能利用先前的执行结果,以达到节约查询计算全过程的时间并减少资源消耗的目的. 目前查询重用技术主要集中在两个方面:     1)查询结果重用         ...

  3. 【Windows】Windows Restart Manager 重启管理器

    Restart Manager(以下简称RM)可以减少或避免安装或更新程序所需要的系统重启次数.安装(或更新)过程中需要重启的主要原因是需要更新的某些文件当前正被一些其它程序或服务所使用.RM允许除关 ...

  4. matlab函数列表(A~Z)【转】

    A a abs 绝对值.模.字符的ASCII码值acos 反余弦acosh 反双曲余弦acot 反余切acoth 反双曲余切acsc 反余割acsch 反双曲余割align 启动图形对象几何位置排列工 ...

  5. 【codevs1380】没有上司的舞会 树形dp

    题目描述 Ural大学有N个职员,编号为1~N.他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.每个职员有一个快乐指数.现在有个周年庆宴会,要求与会职员的快乐指数 ...

  6. Qt——设计颜色编辑选取对话框

    Qt中已经有一些封装好的对话框,比如QMessageBox.QColorDialog等,使用起来快捷方便,但缺点是我们无法为它们自定义样式,所以可能难以“融入”我们的项目.既然如此,那就自己做一个把. ...

  7. FullCalendar(日程管理控件)

    (以下是我学习FullCalendar控件时,网络上收集的一些资料) jQuery.fullCalendar官方网址: http://arshaw.com/fullcalendar/ http://a ...

  8. BZOJ4765 普通计算姬(分块+树状数组)

    对节点按编号分块.设f[i][j]为修改j号点对第i块的影响,计算f[i][]时dfs一遍即可.记录每一整块的sum.修改时对每一块直接更新sum,同时用dfs序上的树状数组维护子树和.查询时累加整块 ...

  9. (转)Ubuntu 12.04 LTS安装VMware Tools实现linux和window 互相复制:无法找到kernel header path的问题

    Ubuntu 12.04 LTS安装VMware Tools无法找到kernel header path的问题   ubuntuvmware Ubuntu 12.04 安装 VMware Tools, ...

  10. [WC2005]双面棋盘

    description 洛谷 给出一个\(n\times n\)的黑白棋盘. \(m\)次操作,每次将一个格子进行颜色翻转,求每次操作后的黑白四连通块数. data range \[n\le 200, ...