「51nod 1647」小Z的trie

NOIP 编号为 ZJ-267 的小 Z 在 NOIP 中 AK 啦!

小 Z 打算去冲击省选,于是开始学习 trie 。

有一天,他得到了 NN 个字符串。

他先建立一个根节点,对于每一个字符串,他都从根节点开始一点点插入。

小 Z 不满足于此。他的大脑里盘旋着 MM 个问题:

如果给定一个二元组 (s,t)(s,t)sstt 都是 trie 中的节点且 sstt 的祖先),存在多少个二元组 (x,y)(x,y)xxyy 都是 trie 中的节点且 xxyy 的祖先),满足 ss ~ tt 路径上的字符串和 xx ~ yy 路径上的字符串完全一样?

注意 ss 可以等于 ttxx 也可以等于 yy

Constraints

1N,M1000001\leq N,M \leq 1000001sum10000001\leq sum \leq 1000000

Solution

先构建出 trie ,然后在 trie 上面建 sam。分别需要记录下原串的每个节点在 trie 上的位置和 trie 上的每个节点在 sam 上的位置。

对于一个询问,从 tt 对应在 sam 上面的节点开始,在 parent 树上跳直到深度最浅的满足节点对应长度不小于询问串的节点为止,该节点的 right 集合大小即为答案。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int N=1e6+5;
int n,m,p,l,r,cnt,length,head,tail;
int pos[N],spos[N],len[N];
char s[N];
int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
struct sam
{
int size,root,len;
int mx[N*2],fa[N*2],sz[N*2],ch[N*2][26];
int c[N],id[N*2],f[N*2][21];
sam()
{
size=root=1;
memset(sz,0,sizeof(sz));
memset(ch,0,sizeof(ch));
}
int ins(int c,int x)
{
int np=++size;mx[np]=mx[x]+1;
len=max(len,mx[np]);sz[np]=1;
while(x&&!ch[x][c])ch[x][c]=np,x=fa[x];
if(!x)fa[np]=root;
else
{
int y=ch[x][c];
if(mx[y]==mx[x]+1)fa[np]=y;
else
{
int nq=++size;
memcpy(ch[nq],ch[y],sizeof(ch[y]));
mx[nq]=mx[x]+1;
fa[nq]=fa[y];fa[y]=fa[np]=nq;
while(x&&ch[x][c]==y)ch[x][c]=nq,x=fa[x];
}
}
return np;
}
void build()
{
for(int i=1;i<=size;i++)c[mx[i]]++;
for(int i=1;i<=len;i++)c[i]+=c[i-1];
for(int i=1;i<=size;i++)id[c[mx[i]]--]=i;
for(int i=size;i>=1;i--)sz[fa[id[i]]]+=sz[id[i]];
for(int i=1;i<=size;i++)
{
int x=id[i];f[x][0]=fa[x];
for(int j=1;j<=20;j++)f[x][j]=f[f[x][j-1]][j-1];
}
}
int find(int x,int len)
{
for(int i=20;i>=0;i--)
if(mx[f[x][i]]>=len)x=f[x][i];
return sz[x];
}
}S;
struct node{int id,np;}t,q[N];
struct trie
{
int sz,ch[N][26];
trie(){sz=0;memset(ch,0,sizeof(ch));}
void insert(char *s,int n)
{
int cur=0;
for(int i=0;i<n;i++)
{
int c=s[i]-'a';
if(!ch[cur][c])ch[cur][c]=++sz;
cur=ch[cur][c];pos[++cnt]=cur;
}
}
void bfs()
{
q[tail++]=(node){0,1};
while(head!=tail)
{
t=q[head++];
int u=t.id,last=t.np;
for(int c=0;c<26;c++)
{
if(!ch[u][c])continue;
int np=S.ins(c,last);
spos[ch[u][c]]=np;
q[tail++]=(node){ch[u][c],np};
}
}
}
}T;
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
scanf("%s",s);
length=strlen(s);
len[i]=len[i-1]+length;
T.insert(s,length);
}
T.bfs();S.build();
m=read();
while(m--)
{
p=read();l=read();r=read();
printf("%d\n",S.find(spos[pos[r+len[p-1]]],r-l+1));
}
return 0;
}