【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树上树链求并. ...
随机推荐
- 如何将revit模型背景设置为黑色
Revit软件建模窗口默认的背景色为白色,在用惯了CAD的新用户转到Revit软件的时候,会对Revit白色的背景不太适应,跟AutoCAD一样,Revit提供自定义工作区背景颜色的功能--其实,你只 ...
- hadoop权威指南学习(一) - 天气预报MapReduce程序的开发和部署
看过Tom White写的Hadoop权威指南(大象书)的朋友一定得从第一个天气预报的Map Reduce程序所吸引, 殊不知,Tom White大牛虽然在书中写了程序和讲解了原理,但是他以为你们都会 ...
- XMAL定义后台数据
头部调用程序集xmlns:sys="clr-namespace:System;assembly=mscorlib" <Window.Resources><!--定 ...
- loopback文件系统
回环设备(loop-back devices) 实验环境 centos7.2 回环设备( 'loopback device')允许用户以一个普通磁盘文件虚拟一个块设备.(磁盘文件 --> 块设备 ...
- 阿里云centos7.x 打开80端口(转)
本文转自:https://blog.csdn.net/tengqingyong/article/details/82805053 一 :阿里云centos7.x用iptables打开80端口 1.安装 ...
- 12C -- ORA-12850: 无法在所有指定实例上分配从属进程: 需要 2, 已分配 1
使用客户端连接到oracle 12.2.0.1 rac数据库,报以下错误信息: ORA-12850: 无法在所有指定实例上分配从属进程: 需要 2, 已分配 1 因为没有mos账号,只好谷歌一下了.找 ...
- Effective Java 第三版——52. 明智而审慎地使用重载
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- LaTeX语法笔记
1.单词之间用空格分隔,段落之间用一整空行分隔,但是,如果在多输入空格或者空行也没有用处,系统还是把它当做一个空格或空行. 2.双引号:左侧用``(键盘左上角那个符号),右侧用'',即: ``'' , ...
- Atiitt 使用java语言编写sql函数或存储过程
Atiitt 使用java语言编写sql函数或存储过程 1.1. java编写sql函数或存储过程的机制1 1.2. Java编写sp的优点1 1.3. 支持java源码,class文件,blog f ...
- 不平衡学习 Learning from Imbalanced Data
问题: ICC警情数据分类不均,30+分类,最多的分类数据数量1w+条,只有10个类别数量超过1k,大部分分类数量少于100条. 解决办法: 下采样:通过非监督学习,找出每个分类中的异常点,减少数据. ...