【CF710F】String Set Queries(二进制分组,AC自动机)

题面

洛谷

CF

翻译:

你有一个字符集合\(D\),初始为空,

有三种操作:

往\(D\)中加入一个串;从\(D\)中删除一个串;给定一个串\(S\),询问\(D\)中的串在\(S\)中总共出现了多少次。

题解

询问显然就是将\(S\)放在所有\(D\)构成的\(AC\)自动机上跑。

所以我们需要一种方法,可以动态的支持\(AC\)自动机的插入以及删除。

先考虑删除,这个很好办,我们可以维护两个\(AC\)自动机,一个记录插入,一个记录删除,将串在两个上面分别跑再做差就好了。这样子删除也变成了插入。

那么如何插入?

我们对于串二进制分组,因为串和串之间是独立的,所以可以对于每一组的串建立一个\(AC\)自动机,合并块的时候直接重构\(AC\)自动机就好了。

写起来很爽啊。我又回到了C++STL选手???string真好用

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define MAX 300300
#define pb push_back
struct Node{int son[26],fail,v;}t[MAX];
int St[MAX],top;
int NewNode(){return St[top--];}
void Insert(int u,string s)
{
for(int i=0,l=s.length();i<l;++i)
{
if(!t[u].son[s[i]-97])t[u].son[s[i]-97]=NewNode();
u=t[u].son[s[i]-97];
}
t[u].v+=1;
}
void Del(int rt)
{
if(!rt)return;
for(int i=0;i<26;++i)
Del(t[rt].son[i]),t[rt].son[i]=0;
t[rt].fail=t[rt].v=0;St[++top]=rt;
}
struct Group
{
vector<string> p;int tot,rt;
void insert(string s){p.pb(s);++tot;}
void clear(){Del(rt);rt=NewNode();p.clear();tot=0;}
void Build()
{
Del(rt);rt=NewNode();
for(int i=0;i<tot;++i)Insert(rt,p[i]);
queue<int> Q;t[rt].fail=rt;
for(int i=0;i<26;++i)
if(t[rt].son[i])Q.push(t[rt].son[i]),t[t[rt].son[i]].fail=rt;
while(!Q.empty())
{
int u=Q.front();Q.pop();
for(int i=0;i<26;++i)
if(t[u].son[i])
{
int p=t[u].fail,v=t[u].son[i];
while(p!=rt&&!t[p].son[i])p=t[p].fail;
if(t[p].son[i])t[v].fail=t[p].son[i];
else t[v].fail=rt;
Q.push(v);
t[v].v+=t[t[v].fail].v;
}
}
}
int Query(string s)
{
int ret=0,u=rt;
for(int i=0,l=s.length();i<l;++i)
{
int c=s[i]-97;
if(t[u].son[c])u=t[u].son[c];
else
{
int p=t[u].fail;
while(p!=rt&&!t[p].son[c])p=t[p].fail;
if(t[p].son[c])u=t[p].son[c];
else u=rt;
}
ret+=t[u].v;
}
return ret;
}
}A[20],B[20];
int tp1,tp2;
void Insert(string s)
{
++tp1;A[tp1].clear();A[tp1].insert(s);
while(tp1>1&&A[tp1].tot==A[tp1-1].tot)
{
for(int i=0;i<A[tp1].tot;++i)A[tp1-1].insert(A[tp1].p[i]);
A[tp1--].clear();
}
A[tp1].Build();
}
void Delete(string s)
{
++tp2;B[tp2].clear();B[tp2].insert(s);
while(tp2>1&&B[tp2].tot==B[tp2-1].tot)
{
for(int i=0;i<B[tp2].tot;++i)B[tp2-1].insert(B[tp2].p[i]);
B[tp2--].clear();
}
B[tp2].Build();
}
int Query(string s)
{
int ret=0;
for(int i=1;i<=tp1;++i)ret+=A[i].Query(s);
for(int i=1;i<=tp2;++i)ret-=B[i].Query(s);
return ret;
}
int m,opt;
string s;
int main()
{
ios::sync_with_stdio(false);
for(int i=1;i<MAX;++i)St[++top]=i;
cin>>m;
while(m--)
{
cin>>opt>>s;
if(opt==1)Insert(s);
if(opt==2)Delete(s);
if(opt==3)cout<<Query(s)<<endl;
}
return 0;
}

【CF710F】String Set Queries(二进制分组,AC自动机)的更多相关文章

  1. CF710F String Set Queries

    CF710F String Set Queries 支持字符串的插入和删除...SAM也干不了这个事 所以可以用cdq分治+AC自动机O(nlogn)解决 但是本题强制在线~~~ 我们还有一个工具,叫 ...

  2. Codeforces963C Frequency of String 【字符串】【AC自动机】

    题目大意: 给一个串s和很多模式串,对每个模式串求s的一个最短的子串使得这个子串中包含至少k个该模式串. 题目分析: 均摊分析,有sqrt(n)种长度不同的模式串,所以有关的串只有msqrt(n)种. ...

  3. ZOJ3784 String of Infinity 高大上的AC自动机 数据原来这么水啊!不算输入输出只有5-7行

    找给定s集合里面word全部是同一个字符的,这样的word有几个,如果数量<m就yes,否则就no.#include<iostream> #include<cstring> ...

  4. 模板汇总——AC自动机

    AC自动机 模板题 HDU-2222 Keywords Search #include<bits/stdc++.h> using namespace std; #define LL lon ...

  5. AC自动机

    AC自动机,全称Aho-Corasick自动机.如果没记错的话好像就是前缀自动机. 其实AC自动机就是KMP上树的产物.理解了KMP,那AC自动机应该也是很好理解的. 与KMP类似,AC自动机也是扔一 ...

  6. 【Codeforces710F】String Set Queries (强制在线)AC自动机 + 二进制分组

    F. String Set Queries time limit per test:3 seconds memory limit per test:768 megabytes input:standa ...

  7. CodeForces - 710F:String Set Queries (二进制分组 处理 在线AC自动机)

    ou should process m queries over a set D of strings. Each query is one of three kinds: Add a string ...

  8. CF710F-String Set Queries【AC自动机,二进制分组】

    正题 题目链接:https://www.luogu.com.cn/problem/CF710F 题目大意 \(T\)次操作 往集合中加入一个字符串 往集合中删除一个字符串 给出一个模式串求出现的集合里 ...

  9. Codeforces 710F - String Set Queries(AC 自动机)

    题面传送门 题意:强制在线的 AC 自动机. \(n,\sum|s|\leq 3\times 10^5\) 如果不是强制在线那此题就是道 sb 题,加了强制在线就不那么 sb 了. 这里介绍两种做法: ...

随机推荐

  1. Revit开发小技巧-连接类

    该类用来连接两个Element.备注一下防止忘记.

  2. python通讯录系统

    ---恢复内容开始--- 对于一般的通讯录系统,主要有两个参数:姓名和电话号码,所以可以利用python编程里面的字典来进行建立之间的所属关系, 可以利用以下代码简单实现: print('|--- 欢 ...

  3. Linux加密到K8S中

    文件名字 test.conf 加密:  base64 --wrap=0 aaa.conf 把得到的密钥填入配置文件当中即可

  4. c++ 整数和字符串的转化

    一.string转int的方式 采用最原始的string, 然后按照十进制的特点进行算术运算得到int,但是这种方式太麻烦,这里不介绍了. 采用标准库中atoi函数. "; int a = ...

  5. 多线程分段下载研究的python实现(一)

    我一直对下载文件比较感兴趣.现在我下载文件大部分是用迅雷,但迅雷也有一些不如意的地方,内存占用大,一些不必要的功能太多,不可定制.尤其是最后一点.现在有些下载对useragent,cookie,aut ...

  6. Linux系统下安装jdk1.8

    JDK安装分为两种方式  一种是解压tar.gz配置安装, 一种是rpm安装,我这里是tar.gz安装方式 一.首先在oracle官方网下载jdk,网址如下:http://www.oracle.com ...

  7. 安装配置php

    安装PHP       1.安装PHP       yum install php   #根据提示输入Y直到安装完成        2.安装PHP组件,使PHP支持 MySQL.PHP支持FastCG ...

  8. Docker容器和本机之间的文件传输 使用Docker部署Tomcat项目

    Docker容器和本机之间的文件传输. http://blog.csdn.net/leafage_m/article/details/72082011 使用Docker部署Tomcat项目 http: ...

  9. jsweb常用代码

    <script> $(function (){ $.ajax({ url: 'https://test.com:8080/api/v1/users?query_not_auth=100&a ...

  10. arcgis 10.3中文版安装教程、配置及常见问题(百度的有些错误)

    参考的: 1.http://wenku.baidu.com/link?url=W-wo_lEMvzHxF19w91X7H0WDjyCQ16DjGu4ViaZ4-eVPr0NTU-LrZTPK1oyzT ...