SPOJ 7258 Lexicographical Substring Search(后缀自动机)

题目链接:http://www.spoj.com/problems/SUBLEX/

题意:给定一个字符串,每次询问第K小的串。

思路:建立自动机。cnt[p]=sigama(cnt[son[p][i]])+1。







const int KIND=26;

char s[N];

int pre[N],Lth[N],son[N][KIND+1];

i64 cnt[N];

int e,n,last;



void insert()

{

    clr(son,-1); e=0;

    pre[e]=-1; Lth[e]=0; last=e++;

    int i,r,p,q,u,x;

    FOR0(i,n)

    {

        x=s[i]-'a';

        u=last; pre[e]=-1; Lth[e]=i+1; last=p=e++;

        for(;u!=-1&&son[u][x]==-1;u=pre[u]) son[u][x]=p;

        if(u==-1) pre[p]=0;

        else

        {

            q=son[u][x];

            if(Lth[q]==Lth[u]+1) pre[p]=q;

            else

            {

                pre[e]=pre[q]; Lth[e]=Lth[u]+1;

                memcpy(son[e],son[q],sizeof(son[e]));

                r=e++;

                pre[p]=pre[q]=r;

                for(;u!=-1&&son[u][x]==q;u=pre[u]) son[u][x]=r;

            }

        }

    }

}



int d[N],Q[N];

char transChar[N];



void init()

{

    int i,j,k,p;

    FOR0(i,n+1) d[i]=0;

    FOR0(i,e) d[Lth[i]]++;

    FOR1(i,n) d[i]+=d[i-1];

    FOR0(i,e) Q[--d[Lth[i]]]=i;

    FORL0(i,e-1)

    {

        p=Q[i]; cnt[p]=1; k=0;

        FOR0(j,KIND) if(son[p][j]!=-1)

        {

            cnt[p]+=cnt[son[p][j]];

            son[p][k++]=son[p][j];

            transChar[son[p][j]]=j+'a';

        }

        son[p][k]=-1;

    }

}



int main()

{

    RD(s); n=strlen(s); insert(); init();

    int Q,len,i,p,q;

    i64 K;

    RD(Q);

    while(Q--)

    {

        RD(K); p=0; len=0;

        while(K)

        {

            i=0;K--;

            while(son[p][i]!=-1)

            {

                q=son[p][i];

                if(K>=cnt[q]) K-=cnt[q];

                else

                {

                    s[len++]=transChar[q];p=q;

                    break;

                }

                i++;

            }

        }

        s[len]=0;

        puts(s);

    }

}

  

你可能感兴趣的:(substring)