[CF710F]String Set Queries

codeforces

description

维护一个字符串集合,支持加入一个串,删除一个串,查询集合中的串在给出串中出现了多少次。
强制在线。

sol

二进制分组。维护\(\log\)\(\mbox{AC}\)自动机,每插入一个串后依次合并,并重建\(\mbox{fail}\),保证每个大小的\(\mbox{AC}\)自动机只存在一个。
有删除操作?注意到这里的答案是具有可减性的,所以再开一个二进制分组表示已删除的串,查询时就用两个答案相减即可。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 3e5+5;
struct AC{
    int son[26][N],end[N],tr[26][N],fa[N],cnt[N],tot;
    int rt[N],sz[N],top;queue<int>Q;
    void getfail(int RT){
        for (int i=0;i<26;++i)
            if (son[i][RT]) fa[tr[i][RT]=son[i][RT]]=RT,Q.push(tr[i][RT]);
            else tr[i][RT]=RT; 
        while (!Q.empty()){
            int u=Q.front();Q.pop();
            for (int i=0;i<26;++i)
                if (son[i][u]){
                    tr[i][u]=son[i][u],fa[tr[i][u]]=tr[i][fa[u]];
                    Q.push(tr[i][u]);
                }else tr[i][u]=tr[i][fa[u]];
            cnt[u]=end[u]+cnt[fa[u]];
        }
    }
    int merge(int x,int y){
        if (!x||!y) return x|y;
        end[x]+=end[y];
        for (int i=0;i<26;++i) son[i][x]=merge(son[i][x],son[i][y]);
        return x;
    }
    void insert(char *s,int n){
        rt[++top]=++tot;sz[top]=1;int x=rt[top];
        for (int i=1;i<=n;++i){
            if (!son[s[i]-'a'][x]) son[s[i]-'a'][x]=++tot;
            x=son[s[i]-'a'][x];
        }
        end[x]=1;
        while (sz[top]==sz[top-1]){
            --top;
            rt[top]=merge(rt[top],rt[top+1]);sz[top]+=sz[top+1];
        }
        getfail(rt[top]);
    }
    int query(char *s,int n){
        int res=0;
        for (int i=1;i<=top;++i)
            for (int j=1,x=rt[i];j<=n;++j)
                x=tr[s[j]-'a'][x],res+=cnt[x];
        return res;
    }
}T1,T2;
char s[N];
int main(){
    int m=gi();while (m--){
        int op=gi();scanf("%s",s+1);int n=strlen(s+1);
        if (op==1) T1.insert(s,n);
        if (op==2) T2.insert(s,n);
        if (op==3) printf("%d\n",T1.query(s,n)-T2.query(s,n)),fflush(stdout);
    }
    return 0;
}

转载于:https://www.cnblogs.com/zhoushuyu/p/9468751.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值