字符串(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;
}
posted @ 2019-08-19 16:29  Mistletoes  阅读(197)  评论(0编辑  收藏  举报