codeforces 710f String Set Queries ac自动机 二进制分组

来源:互联网 发布:php判断是否为素数 编辑:程序博客网 时间:2024/06/06 12:50

题意:维护一个字符串集合,支持插入一个串,删除一个串,询问集合中的串在给出的串中出现多少次,一个串出现多次算多次。并且不会有两次插入的串相同。强制在线。

考虑没有删除的情况,将插入串的个数二进制拆分,对于每2k 个串维护一个ac自动机。
这样共有log个ac自动机
。插入时如果当前ac自动机中串的个数和上一个个数相同,那么合并两个自动机。每个字符串只会被合并log 次。

有删除时同样维护一个删除串的这样的东西,查询时减一下就行了。

#include <bits/stdc++.h>using namespace std;#define N 310000int m,cnt;char s[N];struct acauto{    int ch[N][27],fail[N],en[N],en1[N],cnt;    int num[31],root[31],top;    queue<int>que;    void acmatch(int x)    {        que.push(x);        while(!que.empty())        {            int tmp=que.front();que.pop();            for(int i=1;i<=26;i++)                if(ch[tmp][i])                {                    int t=fail[tmp],t1=ch[tmp][i];                    while(t&&!ch[t][i])t=fail[t];                    fail[t1]=t ? ch[t][i]:x;                    que.push(t1);                    en1[t1]=en1[fail[t1]]+en[t1];                }        }    }    int merge(int x,int y)    {        if(!x||!y)return x+y;        en[x]=en[x]|en[y];        for(int i=1;i<=26;i++)            ch[x][i]=merge(ch[x][i],ch[y][i]);        return x;    }    void insert()    {        scanf("%s",s+1);int len=strlen(s+1);        root[++top]=++cnt;        int now=root[top];        for(int i=1,t;i<=len;i++)        {            if(!ch[now][t=s[i]-'a'+1])                ch[now][t]=++cnt;            now=ch[now][t];        }        en[now]=1;num[top]=1;        acmatch(root[top]);        while(top&&num[top]==num[top-1])        {            merge(root[top-1],root[top]);            acmatch(root[top-1]);            num[top-1]+=num[top];top--;        }    }    int query(int len)    {        int ret=0;        for(int i=1;i<=top;i++)        {            for(int now=root[i],j=1,t;j<=len;j++)            {                t=s[j]-'a'+1;                while(now&&!ch[now][t])                    now=fail[now];                now= now ? ch[now][t]:root[i];                ret+=en1[now];            }        }        return ret;    }}ac1,ac2;int main(){    //freopen("tt.in","r",stdin);    scanf("%d",&m);    for(int t;m--;)    {        scanf("%d",&t);        if(t==1)ac1.insert();        else if(t==2)ac2.insert();        else         {            scanf("%s",s+1);int len=strlen(s+1);            printf("%d\n",ac1.query(len)-ac2.query(len));            fflush(stdout);        }    }    return 0;
0 0
原创粉丝点击