hdu4622-Reincarnation(后缀自动机)

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.
 
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.
 
Output
For each test cases,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
 
 

题意: 给一个字符串长度最大2000,给出Q个查询[l,r]包含多少种连续的子串。
解析: 后缀自动机轻松过,先对查询离线排序,对于左端点相同的建立一个后缀自动
机,字符串长度最大只有2000,所以最后只用建2000个,每个sam插入的字符最多也就
2000,时间肯定是够的。

代码

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=4005;
struct SAM
{
    int ch[maxn][26];
    int pre[maxn],step[maxn];
    int last,id;
    void init()
    {
        last=id=0;
        memset(ch[0],-1,sizeof(ch[0]));
        pre[0]=-1; step[0]=0;
    }
    void Insert(int c) //字符转化为数
    {
        int p=last,np=++id;
        step[np]=step[p]+1;
        memset(ch[np],-1,sizeof(ch[np]));
        while(p!=-1&&ch[p][c]==-1)  ch[p][c]=np,p=pre[p];
        if(p==-1) pre[np]=0;
        else
        {
            int q=ch[p][c];
            if(step[q]!=step[p]+1)
            {
                int nq=++id;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                step[nq]=step[p]+1;
                pre[nq]=pre[q];
                pre[np]=pre[q]=nq;
                while(p!=-1&&ch[p][c]==q) ch[p][c]=nq,p=pre[p];
            }
            else pre[np]=q;
        }
        last=np;
    }
    int GetCnt()
    {
        int ret=0;
        for(int i=id;i>=1;i--) ret+=step[i]-step[pre[i]];
        return ret;
    }
}sam;
char S[maxn/2];
struct Ques
{
    int l,r,id;
    Ques(int l=0,int r=0,int id=0):l(l),r(r),id(id){}
    bool operator < (const Ques& t) const
    {
        if(l!=t.l) return l<t.l;
        return r<t.r;
    }
}q[10005];
int Q,ans[10005];
void solve()
{
    sort(q,q+Q);
    int last;
    for(int i=0;i<Q;i++)
    {
        if(i==0||q[i].l!=q[i-1].l)
        {
            sam.init();
            last=q[i].l;
        }
        for(;last<=q[i].r;last++) sam.Insert(S[last]-'a');
        ans[q[i].id]=sam.GetCnt();
    }
    for(int i=0;i<Q;i++) printf("%d
",ans[i]);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",S+1);
        int len=strlen(S);
        scanf("%d",&Q);
        int l,r,id;
        for(int i=0;i<Q;i++)
        {
            scanf("%d%d",&l,&r);
            q[i]=Ques(l,r,i);
        }
        solve();
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/wust-ouyangli/p/5808999.html