http://acm.hdu.edu.cn/showproblem.php?pid=4622
Reincarnation
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 92 Accepted Submission(s): 7
Problem Description
Now you are back,and have a task to do:
Given you a string s consist of lower-case English letters only,denote f(s) as the 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.
Given you a string s consist of lower-case English letters only,denote f(s) as the 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 line contains 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 number of queries.
Then Q lines follows,each lines contains two integer l, r(1 <= l <= r <= n), denote a query.
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 number of queries.
Then Q lines follows,each lines contains two integer l, r(1 <= l <= r <= n), denote a query.
Output
For each test cases,for each query,print the answer in one line.
思路:求一个字符串的不同子串个数可以用后缀自动机以O(n)的复杂度求出,题目要求的是子串的不同子串的个数,我们当然可以对于每个子串求一次后缀自动机然后再求不同子串个数,但是这样复杂度太大,可以考虑这样一个优化,对于开头L相同的子串(区间),我们并不需要分别构造一次后缀自动机,比如求区间[L1,R1],和[L1,R2](R2>R1),当我们求完[L1,R1]的不同子串个数后,我们不用从头构造子串S[L1,R2]的SAM,而是只需在S[L1,R1]的SAM的基础上再增加子串S[R1+1,R2]之后所得的SAM就可以了,所以我们可以将询问先按L从小到大排序,再按R从小到大排序,李先处理每一个询问即可。以下是代码部分。
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#define maxn 4010
#define Smaxn 26
#define inf 21000000
using namespace std;
struct node
{
node *par,*go[Smaxn];
int num;
int val;
}*root,*tail,que[maxn],*top[maxn];
int tot;
char str[2010];
void add(int c,int l)
{
node *p=tail,*np=&que[tot++];
np->val=l;
while(p&&p->go[c]==NULL)
p->go[c]=np,p=p->par;
if(p==NULL) np->par=root;
else
{
node *q=p->go[c];
if(p->val+1==q->val) np->par=q;
else
{
node *nq=&que[tot++];
*nq=*q;
nq->val=p->val+1;
np->par=q->par=nq;
while(p&&p->go[c]==q) p->go[c]=nq,p=p->par;
}
}
tail=np;
}
int c[maxn],len,ans=0;
void init()
{
memset(que,0,sizeof(que));
tot=0;
len=1;
root=tail=&que[tot++];
}
int solve()
{
ans=0;;
int i;
for(i=tot-1;i>0;i--)
{
ans+=que[i].val-que[i].par->val;
}
return ans;
}
struct ask
{
int x,y,num;
}as[10010];
bool cmp(ask a,ask b)
{
if(a.x==b.x)
{
return a.y<b.y;
}
return a.x<b.x;
}
int Ans[10010];
int main()
{
//freopen("1.in","r",stdin);
//freopen("dd.txt","w",stdout);
int ncase,q,i;
scanf("%d",&ncase);
while(ncase--)
{
scanf("%s",str+1);
scanf("%d",&q);
for(i=1;i<=q;i++)
{
scanf("%d%d",&as[i].x,&as[i].y);
as[i].num=i;
}
sort(as+1,as+q+1,cmp);
as[0].x=-1;
int po=0;
for(i=1;i<=q;i++)
{
if(as[i].x!=as[i-1].x)
{
init();
po=as[i].y;
for(int j=as[i].x;j<=as[i].y;j++)
{
add(str[j]-'a',len++);
}
Ans[as[i].num]=solve();
}
else
{
if(as[i].y==as[i-1].y)
{
Ans[as[i].num]=ans;
}
else
{
for(int j=po+1;j<=as[i].y;j++)
add(str[j]-'a',len++);
Ans[as[i].num]=solve();
}
po=as[i].y;
}
}
for(i=1;i<=q;i++)
printf("%d\n",Ans[i]);
}
return 0;
}