首页 > 代码库 > AC日记——[Noi2011]阿狸的打字机 bzoj 2434

AC日记——[Noi2011]阿狸的打字机 bzoj 2434

2434

 

思路:

  构建ac自动机;

  抽离fail树;

  根据字符串建立主席树;

  在线处理询问;

  询问x在y中出现多少次,等同于y有多少字母的fail能走到x;

  1a,hahahahah;

 

代码:

#include <queue>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define maxn 100005struct TreeNodeType {    int lc,rc,dis;};struct TreeNodeType tree[maxn*21];int n,ch[maxn][26],ff[maxn],fail[maxn],tot;int bel[maxn],bel_[maxn],pn,pla[maxn],head[maxn];int E[maxn<<1],V[maxn<<1],cnt,id[maxn],end[maxn];int root[maxn],tot_,m,times[maxn],sta[maxn],top;char str[maxn];queue<int>que;inline void in(int &now){    char Cget=getchar();now=0;    while(Cget>9||Cget<0) Cget=getchar();    while(Cget>=0&&Cget<=9)    {        now=now*10+Cget-0;        Cget=getchar();    }}void dfs1(int now,int fa){    id[now]=++cnt;    for(int i=head[now];i;i=E[i])    {        if(V[i]==fa) continue;        dfs1(V[i],now);    }    end[now]=cnt;}void tree_build(int &now,int l,int r){    now=++tot_;    if(l==r) return ;    int mid=l+r>>1;    tree_build(tree[now].lc,l,mid);    tree_build(tree[now].rc,mid+1,r);}void tree_add(int pre,int &now,int l,int r,int to){    now=++tot_;    tree[now].dis=tree[pre].dis+1;    if(l==r) return ;    int mid=l+r>>1;    if(to<=mid) tree_add(tree[pre].lc,tree[now].lc,l,mid,to),tree[now].rc=tree[pre].rc;    else tree_add(tree[pre].rc,tree[now].rc,mid+1,r,to),tree[now].lc=tree[pre].lc;}int tree_query(int now,int l,int r,int ll,int rr){    if(l==ll&&rr==r) return tree[now].dis;    int mid=l+r>>1;    if(ll>mid) return tree_query(tree[now].rc,mid+1,r,ll,rr);    else if(rr<=mid) return tree_query(tree[now].lc,l,mid,ll,rr);    else return tree_query(tree[now].lc,l,mid,ll,mid)+tree_query(tree[now].rc,mid+1,r,mid+1,rr);}int main(){    scanf("%s",str),ff[1]=0,tot=1;    int len=strlen(str),now=1,pos,temp;n=len;    for(int i=0;i<len;i++)    {        if(str[i]==P)        {            bel[i]=now,pla[++pn]=now;            continue;        }        if(str[i]==B)        {            now=ff[now];            bel[i]=now;            continue;        }        pos=str[i]-a,bel_[i]=now;        if(!ch[now][pos]) ch[now][pos]=++tot,ff[ch[now][pos]]=now;        now=ch[now][pos],bel[i]=now;    }    que.push(1);int u,v;    while(!que.empty())    {        now=que.front(),que.pop();        for(int i=0;i<26;i++)        {            if(!ch[now][i]) continue;            que.push(ch[now][i]);            if(now==1) fail[ch[now][i]]=1;            else            {                temp=fail[now];                while(temp)                {                    if(ch[temp][i])                    {                        fail[ch[now][i]]=ch[temp][i];                        break;                    }                    temp=fail[temp];                }                if(!temp) fail[ch[now][i]]=1;            }            u=ch[now][i],v=fail[ch[now][i]];            E[++cnt]=head[u],V[cnt]=v,head[u]=cnt;            E[++cnt]=head[v],V[cnt]=u,head[v]=cnt;        }    }    cnt=0,dfs1(1,0),tree_build(root[0],1,n),now=0,pn=0;    for(int i=0;i<len;i++)    {        if(str[i]==B) top--;        else if(str[i]==P) times[++pn]=sta[top];        else        {            tree_add(root[sta[top]],root[i+1],1,n,id[bel[i]]);            sta[++top]=i+1;        }    }    in(m);    for(int i=1;i<=m;i++)    {        in(u),in(v);        printf("%d\n",tree_query(root[times[v]],1,n,id[pla[u]],end[pla[u]]));    }    return 0;}

 

AC日记——[Noi2011]阿狸的打字机 bzoj 2434