【CF587F】Duff is Mad AC自动机+分块
【CF587F】Duff is Mad
题意:给出n个串$s_1,s_2..s_n$,有q组询问,每次给出l,r,k,问你编号在[l,r]中的所有串在$s_k$中出现了多少次。
$\sum|s_i|,q\le 10^5$
题解:先将询问离线,改成前缀相减。然后建出AC自动机,考虑分块。
对于长度$>\sqrt n$的询问串,这种串最多$\sqrt n$个,我们每次可以扫一遍整个fail树,处理出每个节点到根的路径上有多少个询问串中的点。然后将所有串一个一个加入到fail树里,假如加入的串的结束节点到根路径上有a个询问串种的点,则答案+=a。
对于长度$<\sqrt n$的串,我们按编号一个一个处理。我们加入一个串时,要将其结束节点的fail树子树中所有节点的点权都+1。放到DFS序上就是区间+操作。我们再次分块便可做到$O(1)-O(\sqrt n)$的复杂度。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int maxn=100010;
typedef long long ll;
int n,m,B,tot,cnt;
ll sum;
struct node
{
int ch[26],fail;
}p[maxn];
struct query
{
int x,k,org;
query() {}
query(int a,int b,int c) {x=a,k=b,org=c;}
};
int lp[maxn],rp[maxn],q[maxn],pos[maxn],head[maxn],to[maxn],nxt[maxn],p1[maxn],p2[maxn];
ll ans[maxn],s[maxn],sb[1000];
char str[maxn];
vector<query> v1[maxn],v2[maxn];
vector<query>::iterator it;
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
inline void build()
{
int i,u,h=1,t=0;
q[++t]=1;
while(h<=t)
{
u=q[h++];
for(i=0;i<26;i++)
{
if(p[u].ch[i])
{
q[++t]=p[u].ch[i];
if(u==1) p[p[u].ch[i]].fail=1;
else p[p[u].ch[i]].fail=p[p[u].fail].ch[i];
}
else
{
if(u==1) p[u].ch[i]=1;
else p[u].ch[i]=p[p[u].fail].ch[i];
}
}
}
}
bool cmp(const query &a,const query &b)
{
return a.x<b.x;
}
inline void add(int a,int b)
{
to[cnt]=b,nxt[cnt]=head[a],head[a]=cnt++;
}
void dfs(int x)
{
p1[x]=++p2[0];
for(int i=head[x];i!=-1;i=nxt[i]) dfs(to[i]);
p2[x]=p2[0];
}
inline void upd(int a,int b)
{
int i,c=a/B,d=b/B;
if(c==d) for(i=a;i<=b;i++) s[i]++;
else
{
for(i=a;i<c*B+B;i++) s[i]++;
for(i=d*B;i<=b;i++) s[i]++;
for(i=c+1;i<d;i++) sb[i]++;
}
}
int main()
{
n=rd(),m=rd();
int i,j,u,a,b,c;
tot=1;
for(i=1;i<=n;i++)
{
lp[i]=rp[i-1],scanf("%s",str+lp[i]),rp[i]=lp[i]+strlen(str+lp[i]);
for(u=1,j=lp[i];j<rp[i];j++)
{
a=str[j]-'a';
if(!p[u].ch[a]) p[u].ch[a]=++tot;
u=p[u].ch[a];
}
pos[i]=u;
}
build(),B=int(sqrt(double(tot+1)));
for(i=1;i<=m;i++)
{
a=rd(),b=rd(),c=rd();
if(rp[c]-lp[c]>B)
{
if(a!=1) v2[c].push_back(query(a-1,-1,i));
v2[c].push_back(query(b,1,i));
}
else
{
if(a!=1) v1[a-1].push_back(query(c,-1,i));
v1[b].push_back(query(c,1,i));
}
}
memset(head,-1,sizeof(head));
for(i=2;i<=tot;i++) add(p[i].fail,i);
dfs(1);
for(i=1;i<=n;i++)
{
upd(p1[pos[i]],p2[pos[i]]);
for(it=v1[i].begin();it!=v1[i].end();it++)
{
a=(*it).x,b=(*it).k,c=(*it).org;
for(u=1,j=lp[a];j<rp[a];j++)
{
u=p[u].ch[str[j]-'a'];
ans[c]+=(s[p1[u]]+sb[p1[u]/B])*b;
}
}
}
for(i=1;i<=n;i++) if(rp[i]-lp[i]>B&&v2[i].size())
{
memset(s,0,sizeof(s));
for(u=1,j=lp[i];j<rp[i];j++) u=p[u].ch[str[j]-'a'],s[u]++;
for(j=tot;j>=2;j--) s[p[q[j]].fail]+=s[q[j]];
sort(v2[i].begin(),v2[i].end(),cmp);
for(sum=0,j=1,it=v2[i].begin();it!=v2[i].end();it++)
{
a=(*it).x,b=(*it).k,c=(*it).org;
while(j<=a) sum+=s[pos[j++]];
ans[c]+=b*sum;
}
}
for(i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}//
【CF587F】Duff is Mad AC自动机+分块的更多相关文章
- [CF587F]Duff is Mad[AC自动机+根号分治+分块]
题意 给你 \(n\) 个串 \(s_{1\cdots n}\) ,每次询问给出 \(l,r,k\) ,问在 \(s_{l\cdots r}\) 中出现了多少次 \(s_k\) . \(n,q,\su ...
- HDU4787 GRE Words Revenge【AC自动机 分块】
HDU4787 GRE Words Revenge 题意: \(N\)次操作,每次记录一个\(01\)串或者查询一个\(01\)串能匹配多少个记录的串,强制在线 题解: 在线的AC自动机,利用分块来降 ...
- HDU4787 GRE Words Revenge(AC自动机 分块 合并)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4787 Description Now Coach Pang is preparing for ...
- CF587F Duff is Mad(AC自动机+树状数组+分块)
考虑两一个暴力 1 因为询问\([a,b]\)可以拆成\([1,b]\)-\([1,a-1]\)所以把询问离线,然后就是求\([1,x]\)中被\(S_i\)包含的串的数量.考虑当\([1,x-1]- ...
- CF587F Duff is Mad
题目 有趣的思想 首先暴力的话,自然是对每一个询问在\(AC\)自动机上跑一遍\(k\),看看跑出来的节点在\(fail\)树到根的路径上有多少个\(l\)到\(r\)之间的结束标记就好了 我们发现无 ...
- Codeforces 587F - Duff is Mad(根号分治+AC 自动机+树状数组)
题面传送门 第一眼看成了 CF547E-- 话说 CF587F 和 CF547E 出题人一样欸--还有另一道 AC 自动机的题 CF696D 也是这位名叫 PrinceOfPersia 的出题人出的- ...
- CF587F-Duff is Mad【AC自动机,根号分治】
正题 题目链接:https://www.luogu.com.cn/problem/CF587F 题目大意 给出\(n\)个字符串\(s\).\(q\)次询问给出\(l,r,k\)要求输出\(s_{l. ...
- hdu4787 AC自动机加分块
这题说的是 有n次操作 +w 表示读入一个字符串,?p 询问这个字符串的子串在那些模板串中有多少个, http://blog.csdn.net/qq574857122/article/details/ ...
- 一道叉姐的AC自动机鬼题
题面描述丢失了... 给n个串模板串,然后再给你m个串,对于这m个串的每个串,问在[L,R]的模板串中,在多少个串中出现过; 这题的正解是对于后m个串建AC自动机,然后离线,在fail树上树链求并. ...
随机推荐
- Redis源码学习-Master&Slave的命令交互
0. 写在前面 Version Redis2.2.2 Redis中可以支持主从结构,本文主要从master和slave的心跳机制出发(PING),分析redis的命令行交互. 在Redis中,serv ...
- C# CRC16 和汉明重量
最近在看redis之类的pdf,发现redis在做集群的时候,不同的key分到不同的主服务器,其中划分key的算法采用CRC16算法,所以特此整理一下其C#code如下: #region CRC16 ...
- ELK菜鸟手记 (二) - 高级配置之多应用索引过滤
我们在实际的场景中,经常是多个网站或者服务端在一台服务器上,但是如果这些应用全部 记录到一台logstash服务器,大家日志都混在一起不好区分. 有人说,我可以在日志中打项目名,但是这样并不方便. 其 ...
- 【ZH奶酪】为什么Python不需要函数重载?
函数重载的作用是什么? 函数重载主要是为了解决两个问题 可变参数类型 可变参数个数 另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如 ...
- ARP协议具体解释之Gratuitous ARP(免费ARP)
ARP协议具体解释之Gratuitous ARP(免费ARP) Gratuitous ARP(免费ARP) Gratuitous ARP也称为免费ARP.无故ARP.Gratuitous ARP不同于 ...
- mysql主备配置方法
1. 选择两台机器(这里选的centos6.5 final),安装相同版本的mysql yum install mysql ; yum install mysql-server; 2. 启动mysql ...
- JAVA在Windows使用apache commons-csv导出CSV解决方案
一.添加依赖到pom.xml <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependenc ...
- Notes中几个处理多值域的通用函数
1.查找出查找内容在多值域中的索引值 getItemIndex(域名,域值,文档) Public Function getItemIndex(ByVal fieldName As String, By ...
- ASP.NET MVC 自定义处理JSON ActionResult类
1.统一JSON格式处理方式,同时指定ContentType类型,解决低版本浏览器获取json时ContentType为application/json提示下载的问题. public abstract ...
- [k8s]k8s-ceph-statefulsets-storageclass-nfs 有状态应用布署实践
k8s stateful sets storageclass 有状态应用布署实践v2 Copyright 2017-05-22 xiaogang(172826370@qq.com) 参考 由于网上的文 ...