【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自动机+分块的更多相关文章

  1. [CF587F]Duff is Mad[AC自动机+根号分治+分块]

    题意 给你 \(n\) 个串 \(s_{1\cdots n}\) ,每次询问给出 \(l,r,k\) ,问在 \(s_{l\cdots r}\) 中出现了多少次 \(s_k\) . \(n,q,\su ...

  2. HDU4787 GRE Words Revenge【AC自动机 分块】

    HDU4787 GRE Words Revenge 题意: \(N\)次操作,每次记录一个\(01\)串或者查询一个\(01\)串能匹配多少个记录的串,强制在线 题解: 在线的AC自动机,利用分块来降 ...

  3. HDU4787 GRE Words Revenge(AC自动机 分块 合并)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4787 Description Now Coach Pang is preparing for ...

  4. CF587F Duff is Mad(AC自动机+树状数组+分块)

    考虑两一个暴力 1 因为询问\([a,b]\)可以拆成\([1,b]\)-\([1,a-1]\)所以把询问离线,然后就是求\([1,x]\)中被\(S_i\)包含的串的数量.考虑当\([1,x-1]- ...

  5. CF587F Duff is Mad

    题目 有趣的思想 首先暴力的话,自然是对每一个询问在\(AC\)自动机上跑一遍\(k\),看看跑出来的节点在\(fail\)树到根的路径上有多少个\(l\)到\(r\)之间的结束标记就好了 我们发现无 ...

  6. Codeforces 587F - Duff is Mad(根号分治+AC 自动机+树状数组)

    题面传送门 第一眼看成了 CF547E-- 话说 CF587F 和 CF547E 出题人一样欸--还有另一道 AC 自动机的题 CF696D 也是这位名叫 PrinceOfPersia 的出题人出的- ...

  7. CF587F-Duff is Mad【AC自动机,根号分治】

    正题 题目链接:https://www.luogu.com.cn/problem/CF587F 题目大意 给出\(n\)个字符串\(s\).\(q\)次询问给出\(l,r,k\)要求输出\(s_{l. ...

  8. hdu4787 AC自动机加分块

    这题说的是 有n次操作 +w 表示读入一个字符串,?p 询问这个字符串的子串在那些模板串中有多少个, http://blog.csdn.net/qq574857122/article/details/ ...

  9. 一道叉姐的AC自动机鬼题

    题面描述丢失了... 给n个串模板串,然后再给你m个串,对于这m个串的每个串,问在[L,R]的模板串中,在多少个串中出现过; 这题的正解是对于后m个串建AC自动机,然后离线,在fail树上树链求并. ...

随机推荐

  1. vue2.0实现倒计时的插件(时间戳 刷新 跳转 都不影响)

    我发现好多倒计时的插件,刷新都会变成从头再来,于是自己用vue2.0写了一个,测试通过,直接上代码 如下是组件代码: <template> <span :endTime=" ...

  2. Geek地生活,文艺地思考

    本文纯属整理自己零碎杂乱的思绪,和题目无关.           不知觉间,大学已经两年过去了,忙忙碌碌了两年,大一那年參加了学生会编 辑部和艺术团舞蹈队,课余时间的生活总是被舞蹈队排练.參演和编辑部 ...

  3. windows环境下面批量新建文件夹

    md D:批量新建文件夹\2026 md D:批量新建文件夹\2030 md D:批量新建文件夹\2032 md D:批量新建文件夹\1835 md D:批量新建文件夹\1832 电脑桌面新建文档 - ...

  4. Mongodb查询命令详解

    前面我们简单的讲了下find方法,下面来深入的过一下它的用法以及常用的字方法. 下面是mongo中db.user.help()中对find方法的定义和解释: db.user.find([query], ...

  5. ASP.NET MVC 一款可预览、裁剪头像上传组件

    今天介绍一款Web上常用的头像上传组件,常用于头像上传时对用户上传的图片进行裁剪并实时预览,最终效果如下: 源代码结构: Github地址: https://github.com/FrankFan/A ...

  6. 大型互联网架构概述 关于架构的架构目标 典型实现 DNS CDN LB WEB APP SOA MQ CACHE STORAGE

    大型互联网架构概述 目录 架构目标 典型实现 DNS CDN LB WEB APP SOA MQ CACHE STORAGE 本文旨在简单介绍大型互联网的架构和核心组件实现原理. 理论上讲,从安装配置 ...

  7. SQL Server 数据库基础笔记分享(下)

    前言 本文是个人学习SQL Server 数据库时的以往笔记的整理,内容主要是对数据库的基本增删改查的SQL语句操作和约束,视图,存储过程,触发器的基本了解. 注:内容比较基础,适合入门者对SQL S ...

  8. C#调用接口注意要点 socket,模拟服务器、客户端通信 在ASP.NET Core中构建路由的5种方法

    C#调用接口注意要点   在用C#调用接口的时候,遇到需要通过调用登录接口才能调用其他的接口,因为在其他的接口需要在登录的状态下保存Cookie值才能有权限调用, 所以首先需要通过调用登录接口来保存c ...

  9. [Aaronyang] 写给自己的WPF4.5 笔记16[多线程]

      =============潇洒的版权线==========www.ayjs.net===== Aaronyang ========= AY =========== 安徽 六安 杨洋 ======= ...

  10. 视音频数据处理入门:AAC音频码流解析

    ===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB.YUV像素数据处理 视音频数据处理 ...