Codeforces 163E (AC自动机&fail树+dfs序+树状数组)

http://codeforces.com/contest/163/problem/E

实在不好意思,自己画的时候确实有点粗心,感谢大家的提醒。。这次图应该画对了。。

题意:给你几个串,然后后面有些操作,分别是给你一个文本串问哪些模式串在文本串出现了多少次,剩下两个分别就是删除一些字符串,和恢复一些字符串。

做法:AC自动机,(据说还有后缀数组。。不会),如果做过阿狸的打字机这道题应该知道怎么往那方面做。

首先把所有的模式串建AC自动机,然后,建立fail树,就是fail指针反向,然后fail树跑dfs序,然后用树状数组维护。

如图bbaaa abaaab aa, 建 AC自动机,红色fail的指针,涂红和涂蓝的表示一个字符的结尾,黑色的表示结点编号

如图 fail的树,蓝色的表示AC自动机的结点编号,红色和绿色,表示dfs序,黑色的表示一个串的结尾。

在上面的图的基础上,树状的维护就简单了,其实代码就给看本事了,还是看代码吧,不懂的滴滴我;

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int tree[N];
void add(int x,int val)
{
    for(;x<N;x+=x&-x) tree[x]+=val;
}
int query(int x)
{
    int ret=0;
    for(;x;x-=x&-x) ret+=tree[x];
    return ret;
}
int nxt[N][26],fail[N],endd[N];
int tot=0,pos[N];
void Insert(char *s,int id)
{
    int len=strlen(s);
    int u=0;
    for(int i=0;i<len;i++)
    {
        int x=s[i]-'a';
        if(nxt[u][x]==0) nxt[u][x]=++tot;
        u=nxt[u][x];
    }
    endd[u]++;
    pos[id]=u;
}
void build()
{
    queue<int>qu;
    for(int i=0;i<26;i++)
        if(nxt[0][i]!=0) qu.push(nxt[0][i]);
    while(!qu.empty())
    {
        int u=qu.front();qu.pop();
        endd[u]+=endd[fail[u]];
        for(int i=0;i<26;i++)
        {
            if(nxt[u][i]!=0) fail[nxt[u][i]]=nxt[fail[u]][i],qu.push(nxt[u][i]);
            else nxt[u][i]=nxt[fail[u]][i];
        }
    }
}
int n,k,in[N],ou[N],del[N],dfn=0;
vector<int>fait[N];
char str[N];
void dfs(int u)
{
    in[u]=++dfn;
    for(int i=0;i<fait[u].size();i++)
    {
        int v=fait[u][i]; dfs(v);
    }
    ou[u]=dfn;
}

int Mquery(char *s)
{
    int len=strlen(s),u=0,ret=0;
    for(int i=0;i<len;i++)
    {
        int x=s[i]-'a'; u=nxt[u][x];
        if(endd[u])
            ret+=query(in[u]);
    }
    return ret;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    memset(tree,0,sizeof(tree));
    memset(nxt,0,sizeof(nxt));
    memset(fail,0,sizeof(fail));
    memset(endd,0,sizeof(endd));
    memset(del,0,sizeof(del));
    cin>>n>>k;
    for(int i=1;i<=k;i++)
    {
        cin>>str;
        Insert(str,i);
    }
    build();
    for(int i=1;i<=tot;i++) fait[fail[i]].push_back(i);
    dfs(0);
    for(int i=1;i<=tot;i++)
    {
        add(in[i],endd[i]);
        add(in[i]+1,-endd[i]);
    }
    char tt;int tmp;
    for(int i=1;i<=n;i++)
    {
        cin>>tt;
        if(tt=='?')
        {
            cin>>str;
            cout<<Mquery(str)<<endl;
        }
        else if(tt=='-')
        {
            cin>>tmp;
            if(!del[tmp])
            {
                del[tmp]=1;
                add(in[pos[tmp]],-1);
                add(ou[pos[tmp]]+1,1);
            }
        }
        else
        {
            cin>>tmp;
            if(del[tmp])
            {
                del[tmp]=0;
                add(in[pos[tmp]],1);
                add(ou[pos[tmp]]+1,-1);
            }
        }
    }
    return 0;
}
扫描二维码关注公众号,回复: 6214256 查看本文章

猜你喜欢

转载自blog.csdn.net/KXL5180/article/details/89645629