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
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).
Print the answer for each question in a separate line.
5 5 a ab abab ababab b 1 5 1 3 5 1 1 5 2 1 5 3 1 4 5
7 5 6 3 6
参考自:http://blog.csdn.net/u013368721/article/details/46050767
思路:将字符串拼接起来,求一次后缀数组,求后缀数组时保存每个字符属于哪个串,每个串的起始位置,然后我们以sa数组作为下标建立线段树,线段树每个节点代表的区间,保存这个区间内每个字符属于哪个串,然后排序
对于一个询问包含的串K,找到K的起点在sa上的位置,我们可以二分其在sa数组上能延伸的最左端点以及最右端点,使得这之间的所有串与K的lcp都大于等于K的串长。然后我们只要在线段树内统计编号大于等于i且小于等于j的数个数就好了,这个我们只要在每个被完全包含的区间内二分答案,然后累加即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=400100;
const int INF=1000000000;
int N,M;
int sa[maxn],height[maxn],Rank[maxn],t[maxn],t2[maxn],c[maxn];
int str[maxn];
int len[maxn],id[maxn];
int belong[maxn],st[maxn];
int n;
int d[maxn][20];
void build_sa(int m,int n)
{
int *x=t,*y=t2;
for(int i=0;i<m;i++)c[i]=0;
for(int i=0;i<n;i++)c[x[i]=str[i]]++;
for(int i=1;i<m;i++)c[i]+=c[i-1];
for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k;i<n;i++)y[p++]=i;
for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
for(int i=0;i<m;i++)c[i]=0;
for(int i=0;i<n;i++)c[x[y[i]]]++;
for(int i=1;i<m;i++)c[i]+=c[i-1];
for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
swap(x,y);p=1;
x[sa[0]]=0;
for(int i=1;i<n;i++)
x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++);
if(p>=n)break;
m=p;
}
}
void getheight(int n)
{
int k=0;
for(int i=1;i<=n;i++)Rank[sa[i]]=i;
for(int i=0;i<n;i++)
{
if(k)k--;
int j=sa[Rank[i]-1];
while(str[j+k]==str[i+k])k++;
height[Rank[i]]=k;
}
}
void initRMQ(int n)
{
memset(d,0,sizeof(d));
for(int i=0;i<=n;i++)d[i][0]=height[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=0;i+(1<<j)<=n+1;i++)
d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
int LCP(int x,int y)
{
if(x>y)swap(x,y);
int k=0;
while((1<<(k+1))<=(y-x+1))k++;
return min(d[x][k],d[y-(1<<k)+1][k]);
}
int getl(int l,int r,int len)
{
int x=r;
while(l<r)
{
int mid=(l+r)>>1;
int tmp=LCP(mid+1,x);
if(tmp>=len)r=mid;
else l=mid+1;
}
return l;
}
int getr(int l,int r,int len)
{
int x=l;
while(l<r)
{
int mid=(r+l+1)>>1;
int tmp=LCP(x+1,mid);
if(tmp>=len)l=mid;
else r=mid-1;
}
return r;
}
struct IntervalTree
{
vector<int> id[maxn<<2];
void build(int o,int l,int r)
{
id[o].clear();
for(int i=l;i<=r;i++)
id[o].push_back(belong[sa[i]]);
id[o].push_back(INF);
sort(id[o].begin(),id[o].end());
if(l==r)return ;
int mid=(l+r)>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
}
int query(int o,int l,int r,int q1,int q2,int x,int y)
{
if(q1<=l&&r<=q2)
{
int L=lower_bound(id[o].begin(),id[o].end(),x)-id[o].begin()-1;
int R=lower_bound(id[o].begin(),id[o].end(),y+1)-id[o].begin()-1;
return R-L;
}
int mid=(l+r)>>1;
int ans=0;
if(q1<=mid)ans+=query(o<<1,l,mid,q1,q2,x,y);
if(q2>mid)ans+=query(o<<1|1,mid+1,r,q1,q2,x,y);
return ans;
}
}tree;
void solve()
{
tree.build(1,1,n);
while(M--)
{
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
int l=getl(1,Rank[st[k]],len[k]);
int r=getr(Rank[st[k]],n,len[k]);
int ans=tree.query(1,1,n,l,r,x,y);
printf("%d\n",ans);
}
}
char s[maxn];
int main()
{
scanf("%d%d",&N,&M);
n=0;
int n1=27;
for(int i=1;i<=N;i++)
{
scanf("%s",s);
len[i]=strlen(s);
st[i]=n;
for(int j=0;j<len[i];j++)
belong[n]=i,str[n++]=s[j]-'a'+1;
belong[n]=0;
str[n++]=n1++;
}
str[n]=0;
build_sa(n1,n+1);
getheight(n);
initRMQ(n);
solve();
return 0;
}