BZOJ3998 TJOI2015 弦论 后缀自动机

题意:求一个字符串的第K小字串,T=0表示不同位置相同的子串算作一个,T=1算作多个

题意:

建出SAM来跑第K子串,由于一个点所代表的子串在原串出现次数为其子树叶子结点的数量,因而有:

T==1,每个点的|right|=1

T==2,每个点的|right|=子树叶子结点数

BFS跑出所有子串出现的次数即|right|,DFS统计每个节点的出现次数和,具体细节看代码。

然后处理询问即可。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXK=26;
const int MAXN=500000+2;
struct SAM{
    int v,c,s,t;
    SAM *child[MAXK+2],*f;
    SAM(){}
    SAM(int _v):v(_v),f(0),c(0),s(0),t(0){ memset(child,0,sizeof(child));}
}*root,*last=root=new SAM(0),*q[2*MAXN];
int N,K,cnt;
bool T;
char S[MAXN];

void Extend(SAM *&x,int c){
    SAM *p=last,*np=new SAM(p->v+1),*q,*nq;
    while(p && !p->child[c]) p->child[c]=np,p=p->f;

    if(!p) np->f=x;
    else{
        q=p->child[c];
        if(q->v==p->v+1) np->f=q;
        else{
            nq=new SAM(p->v+1);
            memcpy(nq->child,q->child,sizeof(q->child));
            nq->f=q->f,q->f=np->f=nq;
            while(p && p->child[c]==q) p->child[c]=nq,p=p->f;
        }
    }
    last=np;
}

void BFS(SAM *&root){
    SAM *x;
    int l=0,r=1;

    q[0]=root;
    while(l!=r){
        x=q[l++];
        for(int i=0;i<MAXK;i++)
            if(x->child[i] && !x->child[i]->t)
                x->child[i]->t=1,q[r++]=x->child[i];
    }

    for(int i=r-1;i;i--){
        if(!T && q[i]->c) q[i]->c=1;
        q[i]->f->c+=q[i]->c;
    }
}

void DFS(SAM *&x){
    x->t=2,x->s=x->c;
    for(int i=0;i<MAXK;i++)
        if(x->child[i]){
            if(x->child[i]->t!=2) DFS(x->child[i]);
            x->s+=x->child[i]->s;
        }
}

void Query(SAM *&x,int k){
    if(k<=x->c) return;
    k-=x->c;

    for(int i=0;i<MAXK;i++)
        if(x->child[i]){
            if(k<=x->child[i]->s){
                S[++cnt]='a'+i,Query(x->child[i],k);
                return;
            }
            k-=x->child[i]->s;
        }
}

int main(){
    scanf("%s %d %d",S,&T,&K),N=strlen(S);
    for(int i=0;i<N;i++) Extend(root,S[i]-'a'),last->c++;

    BFS(root),root->c=0,DFS(root);

    if(root->s<K) cout << -1 << endl;
    else{
        memset(S,0,sizeof(S));
        Query(root,K);
        printf("%s\n",S+1);
    }

    return 0;
}
View Code

 

posted @ 2017-02-28 23:13  WDZRMPCBIT  阅读(140)  评论(0编辑  收藏  举报