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
5 5
a
generation
known
ababab
b
1 5 1
3 5 1
1 5 2
1 5 3
1 4 5
7
5
6
3
6
Solution to a problem (suffix automata):
Reference Code:
#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+10; int N,Q; char s[maxn]; int nxt[maxn<<1][26],l[maxn<<1],fa[maxn<<1]; int last,tot,cnt[maxn<<1],c[maxn<<1]; int sz,p[maxn],T[maxn<<1]; struct Tr{ int ls,rs; int num; } tr[maxn*40]; 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>>1; if(pos<=mid) Update(tr[x].ls,l,mid,pos); else Update(tr[x].rs,mid+1,r,pos); } int Query(int x,int l,int r,int L,int R) { if(!x) return 0; if(L<=l&&r<=R) return tr[x].num; int mid=l+r>>1,res=0; if(L<=mid) res+=Query(tr[x].ls,l,mid,L,R); if(R>mid) res+=Query(tr[x].rs,mid+1,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=1;i<=tot;++i) cnt[l[i]]++; for(int i=1;i<=tot;++i) cnt[i]+=cnt[i-1]; for(inti = 1 ; i <= all; ++ i) c [cnt [l [i]] -] = i; for ( int i = all x, i> 1 ; - i) x = c [i] t [fa [x]] = Merge (T [x] T [fa [x]]); } Void Init () { last = all = 1 ; sz = 0 ; memset (nxt [all], 0 , sizeof nxt [all]); the [whole] = for [all] = 0 ; } Int newNode () { ++ all; memset (nxt [all], 0 , sizeof nxt [all]); the [whole] = for [all] = 0; 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]+1) last=q; else { nq=NewNode(); l[nq]=l[p]+1; 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]+1; while(p&&!nxt[p][ch]) nxt[p][ch]=np,p=fa[p]; if(!p) fa[np]=1; else { q=nxt[p][ch]; if(l[q]==l[p]+1) fa[np]=q; else { nq=NewNode(); memcpy(nxt[nq],nxt[q],sizeof nxt[q]); fa[nq]=fa[q]; l[nq]=l[p]+1; 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=1;i<=N;++i) { scanf("%s",s); int len=strlen(s); last=1; for(int j=0;j<len;++j) Insert(s[j]-'a',i),Update(T[last],1,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]],1,N,l,r)); } return 0; }
Solution to a problem (AC automaton):
Reference Code:
#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+10; int N,Q; char s[maxn]; int sz,ch[maxn][26],fail[maxn],val[maxn]; int in[maxn],out[maxn],tim,Len[maxn],tot,T[maxn]; vector<int> vec[maxn],ts[maxn]; void Init() { sz=1; tim=tot=0; memset(ch[sz],0,sizeof ch[sz]); memset(val,0,sizeof val); } int idx(char c){return c-'a';} void Insert(char *s,int x) { Len[x]=strlen(s);int u=0; for(int i=0;i<Len[x];++i) { int c=idx(s[i]); ts[x].push_back(c); if(!ch[u][c]){memset(ch[sz],0,sizeof ch[sz]);ch[u][c]=sz++;} u=ch[u][c]; } val[x]=u; } void GetFail() { queue<int> q; fail[0]=0; for(int i=0;i<26;++i) if(ch[0][i]) {fail[ch[0][i]]=0;q.push(ch[0][i]);} while(!q.empty()) { int u=q.front();q.pop(); vec[fail[u]].push_back(u); for(int i=0;i<26;++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=0,len=vec[u].size();i<len;++i) dfs(vec[u][i]); out[u]=tim; } struct Tree{ int ls,rs; int num; } tr[maxn*40]; inline void pushup(int rt) { tr[rt].num=tr[tr[rt].ls].num+tr[tr[rt].rs].num; } inline void Update(int y,int &x,int l,int r,int pos) { tr[++tot]=tr[y];x=tot; if(l==r){tr[x].num++;return;} int mid=l+r>>1; if(pos<=mid) Update(tr[y].ls,tr[x].ls,l,mid,pos); else Update(tr[y].rs,tr[x].rs,mid+1,r,pos); pushup(x); } inline void Build(int y,int &x,int id) { int now=0,last=y; for(int i=0;i<Len[id];++i) { now=ch[now][ts[id][i]]; Update(last,x,1,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>>1,res=0; 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+1,r,L,R); return res; } int main() { scanf("%d%d",&N,&Q); Init(); for(int i=1;i<=N;++i) scanf("%s",s),Insert(s,i); GetFail(); dfs(0); for(int i=1;i<=N;++i) Build(T[i-1],T[i],i); while(Q--) { int l,r,x; scanf("%d%d%d",&l,&r,&x); printf("%d\n",Query(T[l-1],T[r],1,tim,in[val[x]],out[val[x]])); } return 0; }