ProblemDescription
Now you are back,andhave a task to do:
Given you a string s consist of lower-case English letters only,denote f(s) asthe number of distinct sub-string of s.
And you have some query,each time you should calculate f(s[l...r]), s[l...r]means the sub-string of s start from l end at r.
Input
The first linecontains integer T(1<=T<=5), denote the number of the test cases.
For each test cases,the first line contains a string s(1 <= length of s<= 2000).
Denote the length of s by n.
The second line contains an integer Q(1 <= Q <= 10000),denote the numberof queries.
Then Q lines follows,each lines contains two integer l, r(1 <= l <= r<= n), denote a query.
Output
For each testcases,for each query,print the answer in one line.
Sample Input
2
bbaba
5
3 4
2 2
2 5
2 4
1 4
baaba
5
3 3
3 4
1 4
3 5
5 5
Sample Output
3
1
7
5
8
1
3
8
5
1
题目大意:给一个字符串,进行q次询问,求l到r之间的字符串有多少个不同子串。
方法:开始用后缀数组暴力做的,结果果断T掉了。后来看了看CLJ的后缀自动机,然后在网上有查了些后缀自动机的资料(感觉这篇写得不错。http://blog.csdn.net/xuezhongfenfei/article/details/12262941)就试着用后缀自动机写了。对于后缀自动机。我们先将l和r按照l从小到大,排序。对于l相同,r从小到大排序。这样对于l相同的询问,就可以利用后缀自动机的特性往后面加字符得到答案。对于l不同的询问,就重新建立自动机。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<deque>
#include<algorithm>
using namespace std;
struct NODE
{
int left ,right;
int num;
};
struct State
{
State *pre ,*go[26];//pre是上一个可以接收后缀的结点
int val;
};
State * root ,* tail ,que[4010];
NODE nodes[10010];
int ans[10010];
int n ,q ,tot ,sum ,len;
char str[2010];
int cmp(NODE a ,NODE b)
{
if(a.left==b.left)
{
return a.right < b.right;
}
return a.left < b.left;
}
void init()
{
memset(que,0,sizeof(que));
tot = 0;
len = 0;
root = tail = &que[tot++];
}
void add(int w )
{
State *p = tail ,*np = &que[tot++];
np->val = len;
//找到上一个能接受后缀的节点
while(p && p->go[w]==NULL)
{
p->go[w] = np;
p = p->pre;
}
//如果没有找到这样的节点,就将pre指针指向root
if(p==NULL)
{
np->pre = root;
}
//如果找到这样的节点,就把这个节点pre就指向这个节点对应的儿子
else
{
State *q = p->go[w];
if(p->val + 1==q->val)
{
np->pre = q;
}
else
{
State *nq = &que[tot++];
//将q的指针赋值给nq,将nq的pre指向p,将np和q的pre指向nq
*nq = *q;
nq->val = p->val + 1;
q->pre = np->pre = nq;
//同时将p的儿子为w且指向q的全部指向nq
while(p && p->go[w]==q)
{
p->go[w] = nq;
p = p->pre;
}
}
}
tail = np;
}
int solve()
{
sum = 0;
for(int i = tot - 1;i > 0;i--)
{
sum += que[i].val - que[i].pre->val;
}
return sum;
}
int main()
{
int x;
scanf("%d",&n);
while(n--)
{
scanf("%s",str+1);
scanf("%d",&q);
for(int i = 1;i<=q;i++)
{
scanf("%d%d",&nodes[i].left,&nodes[i].right);
nodes[i].num = i;
}
sort(nodes + 1,nodes + q + 1,cmp);
nodes[0].left = -1;
for(int i = 1;i<=q;i++)
{
if(nodes[i].left!=nodes[i-1].left)
{
init();
for(int j = nodes[i].left;j <= nodes[i].right;j++)
{
len++;
add(str[j] - 'a');
}
ans[nodes[i].num] = solve();
x = nodes[i].right + 1;
}
else
{
if(nodes[i].right==nodes[i-1].right)
{
ans[nodes[i].num] = ans[nodes[i-1].num];
}
else
{
for(int j = x;j <= nodes[i].right;j++)
{
len++;
add(str[j] - 'a');
}
ans[nodes[i].num] = solve();
x = nodes[i].right + 1;
}
}
}
for(int i = 1;i <= q;i++)
{
printf("%d\n",ans[i]);
}
}
return 0;
}