What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercase English letters. What is double strange that a phone number can be associated with several bears!

In that country there is a rock band called CF consisting of n bears (including Mike) numbered from 1 to n.

Phone number of i-th member of CF is si. May 17th is a holiday named Phone Calls day. In the last Phone Calls day, everyone called all the numbers that are substrings of his/her number (one may call some number several times). In particular, everyone called himself (that was really strange country).

Denote as call(i, j) the number of times that i-th member of CF called the j-th member of CF.

The geek Mike has q questions that he wants to ask you. In each question he gives you numbers l, r and k and you should tell him the number

Input

The first line of input contains integers n and q (1 ≤ n ≤ 2 × 105 and 1 ≤ q ≤ 5 × 105).

The next n lines contain the phone numbers, i-th line contains a string si consisting of lowercase English letters ().

The next q lines contain the information about the questions, each of them contains integers l, r and k (1 ≤ l ≤ r ≤ n and 1 ≤ k ≤ n).

Output

Print the answer for each question in a separate line.

Examples

Input
5 5
a
ab
abab
ababab
b
1 5 1
3 5 1
1 5 2
1 5 3
1 4 5
Output
7
5
6
3
6

题意:题目给你N个字符串,Q组询问(1<=N , Q<=200000).(∑s[i] <=200000 )
每组询问,l, r,x  : 在第 l个 字符串  到 第r个字符串这(r-l+1)个字符串中,第x个字符串出现的次数。


题解一(后缀自动机):

我们将这N个字符串建立SAM,然后将其parent tree拉出来,那么对于一个节点所表示的单词,他出现的次数就是他的子树的大小,由于题目是要求l~r之间,所以是他的子树中endpos在一定范围内的点的数量。我们建立SAM时,对于第k个字符串,每加入一个节点,就在对应节点的线段树里面的第k个位置加一。 我们用线段树维护每个节点的子树,然后线段树合并。

对于每一个询问,我们只要在对应的子树里面找l~r区间的和就行了。

参考代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>
#define pil pair<int,ll>
#define mkp make_apir
const int INF=0x3f3f3f3f;
const int maxn=2e5+;
int N,Q;
char s[maxn]; int nxt[maxn<<][],l[maxn<<],fa[maxn<<];
int last,tot,cnt[maxn<<],c[maxn<<];
int sz,p[maxn],T[maxn<<]; struct Tr{
int ls,rs;
int num;
} tr[maxn*]; void Update(int &x,int l,int r,int pos)
{
if(!x) x=++sz;
tr[x].num++;
if(l==r) return ;
int mid=l+r>>;
if(pos<=mid) Update(tr[x].ls,l,mid,pos);
else Update(tr[x].rs,mid+,r,pos);
} int Query(int x,int l,int r,int L,int R)
{
if(!x) return ;
if(L<=l&&r<=R) return tr[x].num;
int mid=l+r>>,res=;
if(L<=mid) res+=Query(tr[x].ls,l,mid,L,R);
if(R>mid) res+=Query(tr[x].rs,mid+,r,L,R);
return res;
} int Merge(int x,int y)
{
if(!x||!y) return x+y;
int z=++sz;
tr[z].ls=Merge(tr[x].ls,tr[y].ls);
tr[z].rs=Merge(tr[x].rs,tr[y].rs);
tr[z].num=tr[x].num+tr[y].num;
return z;
} void Mer()
{
for(int i=;i<=tot;++i) cnt[l[i]]++;
for(int i=;i<=tot;++i) cnt[i]+=cnt[i-];
for(int i=;i<=tot;++i) c[cnt[l[i]]--]=i;
for(int i=tot,x;i>;--i) x=c[i],T[fa[x]]=Merge(T[x],T[fa[x]]);
} void Init()
{
last=tot=; sz=;
memset(nxt[tot],,sizeof nxt[tot]);
l[tot]=fa[tot]=;
} int NewNode()
{
++tot;
memset(nxt[tot],,sizeof nxt[tot]);
l[tot]=fa[tot]=;
return tot;
} void Insert(int ch,int x)
{
int p,q,np,nq;
if(nxt[last][ch])
{
p=last;q=nxt[p][ch];
if(l[q]==l[p]+) last=q;
else
{
nq=NewNode();
l[nq]=l[p]+;
memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
fa[nq]=fa[q];fa[q]=nq;
while(p&&nxt[p][ch]==q) nxt[p][ch]=nq,p=fa[p];
last=nq;
}
}
else
{
np=NewNode(),p=last;
last=np; l[np]=l[p]+;
while(p&&!nxt[p][ch]) nxt[p][ch]=np,p=fa[p];
if(!p) fa[np]=;
else
{
q=nxt[p][ch];
if(l[q]==l[p]+) fa[np]=q;
else
{
nq=NewNode();
memcpy(nxt[nq],nxt[q],sizeof nxt[q]);
fa[nq]=fa[q];
l[nq]=l[p]+;
fa[q]=fa[np]=nq;
while(p&&nxt[p][ch]==q) nxt[p][ch]=nq,p=fa[p];
}
}
}
} int main()
{
scanf("%d%d",&N,&Q);
Init();
for(int i=;i<=N;++i)
{
scanf("%s",s);
int len=strlen(s); last=;
for(int j=;j<len;++j) Insert(s[j]-'a',i),Update(T[last],,N,i);
p[i]=last;
}
Mer(); while(Q--)
{
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",Query(T[p[x]],,N,l,r));
} return ;
}

题解二(AC自动机):首先对于多串匹配问题,我们很容易想到AC自动机。在AC自动机的fail树中的每个节点,我们知道他出现的次数就是他的子树的大小。但是这题是要询问在第 l个 字符串  到 第r个字符串这(r-l+1)个字符串中,第x个字符串出现的次数,这我们可以想到主席树的询问历史版本信息的性质,那么我们就可以用主席树去维护AC自动机的fail指针的dfs序。然后我们只要求出第R棵树和地(L-1)棵树的差值就行了。

参考代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>
#define pil pair<int,ll>
#define mkp make_apir
const int INF=0x3f3f3f3f;
const int maxn=2e5+;
int N,Q;
char s[maxn];
int sz,ch[maxn][],fail[maxn],val[maxn];
int in[maxn],out[maxn],tim,Len[maxn],tot,T[maxn];
vector<int> vec[maxn],ts[maxn];
void Init()
{
sz=; tim=tot=;
memset(ch[sz],,sizeof ch[sz]);
memset(val,,sizeof val);
}
int idx(char c){return c-'a';}
void Insert(char *s,int x)
{
Len[x]=strlen(s);int u=;
for(int i=;i<Len[x];++i)
{
int c=idx(s[i]); ts[x].push_back(c);
if(!ch[u][c]){memset(ch[sz],,sizeof ch[sz]);ch[u][c]=sz++;}
u=ch[u][c];
}
val[x]=u;
}
void GetFail()
{
queue<int> q;
fail[]=;
for(int i=;i<;++i)
if(ch[][i]) {fail[ch[][i]]=;q.push(ch[][i]);} while(!q.empty())
{
int u=q.front();q.pop();
vec[fail[u]].push_back(u);
for(int i=;i<;++i)
{
int c=ch[u][i];
if(!c){ch[u][i]=ch[fail[u]][i];continue;}
q.push(c);
fail[c]=ch[fail[u]][i];
}
}
}
void dfs(int u)
{
in[u]=++tim;
for(int i=,len=vec[u].size();i<len;++i)
dfs(vec[u][i]);
out[u]=tim;
} struct Tree{
int ls,rs;
int num;
} tr[maxn*]; inline void Update(int y,int &x,int l,int r,int pos)
{
tr[++tot]=tr[y];tr[tot].num++; x=tot;
if(l==r) return;
int mid=l+r>>;
if(pos<=mid) Update(tr[y].ls,tr[x].ls,l,mid,pos);
else Update(tr[y].rs,tr[x].rs,mid+,r,pos);
}
inline void Build(int y,int &x,int id)
{
int now=,last=y;
for(int i=;i<Len[id];++i)
{
now=ch[now][ts[id][i]];
Update(last,x,,tim,in[now]);
last=x;
}
}
inline int Query(int y,int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tr[x].num-tr[y].num;
int mid=l+r>>,res=;
if(L<=mid) res+=Query(tr[y].ls,tr[x].ls,l,mid,L,R);
if(R>mid) res+=Query(tr[y].rs,tr[x].rs,mid+,r,L,R);
return res;
} int main()
{
scanf("%d%d",&N,&Q);
Init();
for(int i=;i<=N;++i) scanf("%s",s),Insert(s,i);
GetFail();
dfs();
for(int i=;i<=N;++i) Build(T[i-],T[i],i);
while(Q--)
{
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",Query(T[l-],T[r],,tim,in[val[x]],out[val[x]]));
} return ;
}

CF547E Milk and Friends(AC自动机的fail指针上建主席树 或 广义后缀自动机的parent线段树合并)的更多相关文章

  1. BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机 后缀自动机 字符串

    https://www.lydsy.com/JudgeOnline/problem.php?id=3926 广义后缀自动机是一种可以处理好多字符串的一种数据结构(不像后缀自动机只有处理一到两种的时候比 ...

  2. [bzoj3277==bzoj3473]出现k次子串计数——广义后缀自动机+STL

    Brief Description 给定n个字符串,对于每个字符串,您需要求出在所有字符串中出现次数大于等于k次的子串个数. Algorithm Design 先建立一个广义后缀自动机,什么是广义后缀 ...

  3. AC自动机 - 关于Fail指针

    fail指针可以说是AC自动机里最难理解的东西,怎样更好的理解AC自动机的fail指针? 先来看一幅图: 看这幅图上的fail指针是怎么构造的. 树上的词分别是: { he , hers , his ...

  4. UVA - 11107 Life Forms (广义后缀自动机+后缀树/后缀数组+尺取)

    题意:给你n个字符串,求出在超过一半的字符串中出现的所有子串中最长的子串,按字典序输出. 这道题算是我的一个黑历史了吧,以前我的做法是对这n个字符串建广义后缀自动机,然后在自动机上dfs,交上去AC了 ...

  5. 后缀自动机(SAM)+广义后缀自动机(GSA)

    经过一顿操作之后竟然疑似没退役0 0 你是XCPC选手吗?我觉得我是! 稍微补一点之前丢给队友的知识吧,除了数论以外都可以看看,为Dhaka和新队伍做点准备... 不错的零基础教程见 IO WIKI ...

  6. BZOJ 3277 串 (广义后缀自动机)

    3277: 串 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 309 Solved: 118 [Submit][Status][Discuss] De ...

  7. UVA - 11107 Life Forms (广义后缀自动机)

    题意:给你n个字符串,求出在超过一半的字符串中出现的所有子串中最长的子串,按字典序输出. 对这n个字符串建广义后缀自动机,建完后每个字符串在自动机上跑一遍,沿fail树向上更新所有子串结点的出现次数( ...

  8. [Bzoj4566][Haoi2016]找相同字符(广义后缀自动机)

    4566: [Haoi2016]找相同字符 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 861  Solved: 495[Submit][Statu ...

  9. 【BZOJ2806】【CTSC2012】Cheat 广义后缀自动机+二分+Dp

    题目 题目在这里 思路&做法 我们先对标准作文库建广义后缀自动机. 然后对于每一篇阿米巴的作文, 我们首先把放到广义后缀自动机跑一遍, 对于每一个位置, 记录公共子串的长度\((\)即代码和下 ...

随机推荐

  1. 6.2.2 辅助类GenericOptionsParser,Tool和ToolRunner深入解析

    辅助类GenericOptionsParser,Tool和ToolRunner (1)为什么要用ToolRunner 将MapReduce Job配置参数写到java代码里,一旦变更意味着修改java ...

  2. Zabbix-(三)监控主机CPU、磁盘、内存并创建监控图形

    Zabbix-(三)监控主机CPU.磁盘.内存并创建监控图形 一.前言 前文中已经讲述了两种方式对Zabbix的搭建,本文将讲述如何在zaibbx上添加需要监控的主机,以及使用Zabbix自带模板和自 ...

  3. Linux运维利器之ClusterShell

    一.简介 实验室机房有大概百台的服务器需要管理,加上需要搭建Hadoop以及Spark集群等,因此,一个轻量级的集群管理软件就显得非常有必要了.经过一段时间的了解以及尝试,最终选择了clustersh ...

  4. suseoj 1207: 大整数的乘法(java, 大数相乘, C/C++, 大数相乘)

    1207: 大整数的乘法 时间限制: 1 Sec  内存限制: 128 MB提交: 7  解决: 2[提交][状态][讨论版][命题人:liyuansong] 题目描述 求两个不超过200位的非负整数 ...

  5. nyoj 845-无主之地1 (struct)

    845-无主之地1 内存限制:64MB 时间限制:1000ms 特判: No 通过数:8 提交数:16 难度:0 题目描述: 子晓最近在玩无主之地1,他对这个游戏的评价不错,结合了FPS与RPG元素, ...

  6. 【前端新手也能做大项目】:跟我一起,从零打造一个属于自己的在线Visio项目实战【ReactJS + UmiJS + DvaJS】(二)

    本系列教程是教大家如何根据开源js绘图库,打造一个属于自己的在线绘图软件.当然,也可以看着是这个绘图库的开发教程.如果你觉得好,欢迎点个赞,让我们更有动力去做好! 本系列教程重点介绍如何开发自己的绘图 ...

  7. thinking in JAVA 编译记录

    编辑/编译<thinking in JAVA>源代码 一.下载源代码 首先,我阅读的是<thinking in JAVA>第四版,因此按照书中提供的链接找到了mindview主 ...

  8. python2的编码问题小结

    对于python2,经常会遇到编码问题,在此小记一下. Python2默认的编码解码方式是ascii码,这点要牢记. windows系统默认是gbk编码的,可以使用chcp查看:936,那就是GBK简 ...

  9. 2-SAT习题讲解

    2-SAT习题讲解 讲在前面:下述例题不是按照难度顺序的,而且基本就只会讲解建图的过程.下面讲解中$A'$为$A$的反向状态. 一.bzoj习题 例一:$bzoj2199 奶牛议会$ 首先我们考虑本题 ...

  10. 将Swagger2文档导出为HTML或markdown等格式离线阅读

    网上有很多<使用swagger2构建API文档>的文章,该文档是一个在线文档,需要使用HTTP访问.但是在我们日常使用swagger接口文档的时候,有的时候需要接口文档离线访问,如将文档导 ...