CF547E Milk and Friends (built Chairman parent tree line or generalized suffix tree automata merger fail pointer on AC automaton)

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
generation
known
ababab
b
1 5 1
3 5 1
1 5 2
1 5 3
1 4 5
Output
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;
}
View Code

 

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;
}
View Code

 

Guess you like

Origin www.cnblogs.com/songorz/p/11506124.html