码迷,mamicode.com
首页 > 其他好文 > 详细

CF710F String Set Queries

时间:2019-07-13 22:44:11      阅读:104      评论:0      收藏:0      [点我收藏+]

标签:cto   修改   void   using   字符串   style   math   ac自动机   ==   

维护一个字符串集合,支持三种操作:

1.加字符串

2.删字符串

3.查询集合中的所有字符串在给出的模板串中出现的次数

操作数m≤3∗10^5,输入字符串总长度L≤4∗10^6

AC自动机+二进制分组

二进制分组的基本思想是把修改操作按二的次幂分组,遇到修改就在尾部加一个,且与之前的合并(暴力重构),比如之前有23(16+4+2+1)个,加了一个后就变成了24(16+8)个,遇到查询就在每个组内查询,再加起来就好了,所以修改对询问的贡献独立时才能用二进制分组。

这道题对于加的串和删的串分别维护,查询时相减即可。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<iostream>
#include<vector>
using namespace std;
const int N=300005;
struct node
{
    int ch[26],fail,w;
}g;
vector<node> vct[2][30];
int m,t,i,num[2],w[2][30],cnt[2],sz[2][30],q[N],bg,ed,head[N],adj[N],nxt[N];
string s,str[2][N];
bool v[N];
void dfs(int id,int cnt,int x,int w)
{
    w+=vct[id][cnt][x].w;
    vct[id][cnt][x].w=w;
    for(int y=head[x];y;y=nxt[y])
        dfs(id,cnt,adj[y],w);
}
void add(int id)
{
    int i,j,k,x,y,z,len;
    str[id][++num[id]]=s;
    for(i=cnt[id],j=1;i>=1;--i)
    {
        if(!v[j+w[id][i]])
            break;
        j+=w[id][i];
        vct[id][i].clear();
    }
    cnt[id]=i+1;
    w[id][cnt[id]]=j;
    sz[id][cnt[id]]=1;
    vct[id][cnt[id]].clear();
    vct[id][cnt[id]].push_back(g);
    for(k=num[id]-j+1;k<=num[id];++k)
    {
        len=str[id][k].size();
        for(x=y=0;x<len;++x)
        {
            z=str[id][k][x]-a;
            if(!vct[id][cnt[id]][y].ch[z])
            {
                vct[id][cnt[id]][y].ch[z]=sz[id][cnt[id]]++;
                vct[id][cnt[id]].push_back(g);
            }
            y=vct[id][cnt[id]][y].ch[z];
        }
        vct[id][cnt[id]][y].w++;
    }
    bg=1,ed=0;
    for(i=0;i<26;++i)
        if(vct[id][cnt[id]][0].ch[i])
            q[++ed]=vct[id][cnt[id]][0].ch[i];
    while(bg<=ed)
    {
        for(i=0;i<26;++i)
            if(vct[id][cnt[id]][q[bg]].ch[i])
            {
                q[++ed]=vct[id][cnt[id]][q[bg]].ch[i];
                vct[id][cnt[id]][q[ed]].fail=vct[id][cnt[id]][vct[id][cnt[id]][q[bg]].fail].ch[i];
            }
            else
                vct[id][cnt[id]][q[bg]].ch[i]=vct[id][cnt[id]][vct[id][cnt[id]][q[bg]].fail].ch[i];
        ++bg;
    }
    for(i=sz[id][cnt[id]]-1;i>=0;--i)
        head[i]=0;
    for(i=sz[id][cnt[id]]-1;i>0;--i)
    {
        adj[i]=i;
        nxt[i]=head[vct[id][cnt[id]][i].fail];
        head[vct[id][cnt[id]][i].fail]=i;
    }
    dfs(id,cnt[id],0,0);
}
long long work(int id)
{
    int i,j,k,len=s.size();
    long long rtn=0;
    for(i=1;i<=cnt[id];++i)
    {
        for(j=k=0;j<len;++j)
        {
            k=vct[id][i][k].ch[s[j]-a];
            rtn+=vct[id][i][k].w;
        }
    }
    return rtn;
}
int main()
{
    cin>>m;
    for(i=0;(1<<i)<N;++i)
        v[1<<i]=true;
    while(m--)
    {
        cin>>t>>s;
        if(t==1||t==2)
            add(t-1);
        else
        {
            cout<<work(0)-work(1)<<endl;
            cout.flush();
        }
    }
    return 0;
}

 

CF710F String Set Queries

标签:cto   修改   void   using   字符串   style   math   ac自动机   ==   

原文地址:https://www.cnblogs.com/pthws/p/11182371.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!