字符串(AC自动机+fail tree)


题目描述:

题解:

a[i] 实际就是字符串 i 在总集合中出现的次数,很自然地想到fail tree

注意:注释中的那段代码是不能用的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
const int N=2000010;
struct Edge{int v,nxt;}edge[N];
int head[N],cnt;
int ch[N][26],fail[N],word[N],num;
int st[N],ed[N],tot;
int m,l,len[N],bg[N],que,work[N];
ll c[N],mask,ans,val[N],opt[N];
char s[N],str[N];
void add_edge(int u,int v){
    edge[++cnt].v=v;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
}
void insert(char *s,int id){
    int now=0;
    for(int i=0;i<len[id];i++){
        int x=s[i]-'a';
        if(!ch[now][x]) ch[now][x]=++num;
        now=ch[now][x];
    }
    word[id]=now;
}
void get_fail(){
    queue<int> q;
    for(int i=0;i<26;i++){
        if(ch[0][i]) q.push(ch[0][i]);
    }
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int i=0;i<26;i++){
            if(ch[now][i]){
                fail[ch[now][i]]=ch[fail[now]][i];
                q.push(ch[now][i]);
            }
            else ch[now][i]=ch[fail[now]][i];
        }
    }
}
void dfs(int u){
    st[u]=++tot;
    for(int i=head[u];i;i=edge[i].nxt) 
        dfs(edge[i].v);
    ed[u]=tot;
}
void build_fail_tree(){
    for(int i=1;i<=num;i++)
        add_edge(fail[i],i);
    dfs(0);
}
inline int lowbit(int x){return x&(-x);}
void add(int x,int d){
    for(int i=x;i<=tot;i+=lowbit(i))
        c[i]+=d;
}
ll getsum(int x){
    ll sum=0;
    for(int i=x;i>=1;i-=lowbit(i))
        sum+=c[i];
    return sum;
}
void query(int l,int r){
    que++;
    int now=0;
    for(int i=l;i<=r;i++){
        now=ch[now][s[i]-'a'];
        if(work[now]==que)//子串在s中已经出现过 
            ans+=val[now];
        else{
            work[now]=que;
            //val[now]=getsum(ed[now])-getsum(st[now]-1);
            val[now]=getsum(st[now]);
            ans+=val[now];
        }
    }
}
int main(){
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%lld%s",&opt[i],str);
        len[i]=strlen(str);
        bg[i]=l+1;
        insert(str,i);
        for(int j=0;j<len[i];j++)
            s[++l]=str[j];
    }
    get_fail();
    build_fail_tree();
    for(int i=1;i<=m;i++){
        opt[i]^=mask;
        if(opt[i]==1){
            add(st[word[i]],1);
            add(ed[word[i]]+1,-1);
        } //add(st[word[i]],1);
        else if(opt[i]==2){
            add(st[word[i]],-1);
            add(ed[word[i]]+1,1);
        } //add(st[word[i]],-1);
        else if(opt[i]==3){
            ans=0;
            query(bg[i],bg[i]+len[i]-1);
            printf("%lld\n",ans);
            mask^=labs(ans);
        }
    }
    return 0;
}
优质内容筛选与推荐>>
1、Block创建和使用
2、SQL server 如何修改登录名和密码
3、Java基础学习笔记
4、centos6.5 python命令行模式左右建无法使用
5、vim、gvim在windows下中文乱码的终极解决方案【zt】


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号