bzoj2434 阿狸的打字机 fail树+树状数组

来源:互联网 发布:福建公安便民网络 编辑:程序博客网 时间:2024/05/17 20:13

啊为了这道题花了接近半天的时间……主要还是因为自己效率太低……以及太弱……

思路:

m个询问,每个询问x y 问x在y中出现多少次
y–包含串 x–被包含串
求第x个打印的字符串在第y个打印的字符串中出现了多少次。
先建造ac自动机及fail指针,再以fail的反指针建造fail树。
x在y中出现多少次 =查x字符串的末尾指向y的fail反指针有多少=是此时在x的子树中有多少y串中的点=统计子树和
还有一些需要注意的细节,具体看代码:

/**************************************************************    Problem: 2434    User: DD_D    Language: C++    Result: Accepted    Time:668 ms    Memory:16584 kb****************************************************************/#include<cstdio>#include<cstring>#include<queue>#include<algorithm>using namespace std;const int M=1e5+5,N=1e5+5; char s[N];int rt,ch[N][26],ptot,etot,m,len;int to[N],head[N],nxt[N],in[N],out[N],idc,c[N],ans[M],ed[N],fa[N];int fail[N];struct type{    int x,y,id;}a[M];int cmp(type a,type b){    return a.y!=b.y?a.y<b.y:a.x<b.x;}void build(){    int now=rt,cnt=0/**/;    for(int i=1;i<=len;i++){         if(s[i]=='P') ed[++cnt]=now;        else if(s[i]=='B') now=fa[now];             else if(ch[now][s[i]-'a']==-1)                  ch[now][s[i]-'a']=++ptot,fa[ptot]=now,now=ptot;                  else now=ch[now][s[i]-'a'];    }}void get_fail(){    queue<int> q;    fail[rt]=0;    q.push(rt);    //!!!!!建fail的时候一定要记得特判第一层!!!     while(!q.empty()){        int now=q.front();q.pop();        for(int i=0;i<26;i++){            if(ch[now][i]!=-1) {                q.push(ch[now][i]);                fail[ch[now][i]]= now==0?0:ch[fail[now]][i];            }            else ch[now][i]= now==0?0:ch[fail[now]][i];        }    }}void adde(int u,int v){    to[++etot]=v;    nxt[etot]=head[u];    head[u]=etot;}void dfs(int u){    in[u]=++idc;    for(int i=head[u];i;i=nxt[i]) dfs(to[i]);    out[u]=idc;}void init(){    ptot=0;    memset(ch,-1,sizeof(ch));}void add(int x,int d){    for(int i=x;i<=idc;i+=i&(-i))    c[i]+=d;}int query(int l,int r){    int a1=0,a2=0;    for(int i=l-1;i>=1;i-=i&(-i))    a1+=c[i];    for(int i=r;i>=1;i-=i&(-i))    a2+=c[i];    return a2-a1;}//solve的步骤://y完了后,要查x字符串的末尾指向它的fail反指针有多少,也就是此时在x的子树中//有多少y串中的点,也就是统计子树和 //不用担心x的子树里有除y以外其他串的原因:y字符串不是从P开始而是从头开始//所以现在没有因为B而被删的字符都属于y字符串 void solve(){    int now=rt,cnt=0,k=1;    for(int i=1;i<=len;i++){         if(s[i]=='P'){            cnt++;            if(cnt==a[k].y){                for(;a[k].y==cnt;k++)        ans[a[k].id]=query(in[ed[a[k].x]],out[ed[a[k].x]]);            }        }         else if(s[i]=='B') add(in[now],-1),now=fa[now];             else now=ch[now][s[i]-'a'],add(in[now],1);    }}int main(){    init();    scanf("%s",s+1);    len=strlen(s+1);    build();    get_fail();    for(int i=1;i<=ptot;i++)    adde(fail[i],i);    dfs(rt);    scanf("%d",&m);    for(int i=1;i<=m;i++){        scanf("%d%d",&a[i].x,&a[i].y);        a[i].id=i;    }    sort(a+1,a+1+m,cmp);    solve();    for(int i=1;i<=m;i++)    printf("%d\n",ans[i]);    return 0;} 
阅读全文
0 0