【后缀自动机】[SPOJ SUBLEX]Lexicographical Substring Search

题目大意,给定一个字符串求第K大的子串
首先给这个字符串建立SAM然后发现实际上每一个节点就可以表示一个子串然后实际上就是从root到这个节点的路径,然后按照splay的那种思路建立size然后用k去找在当前节点的哪一个子树中,然后减去当前子树的size就可以得到在下一个子树中的位置,然后重复当前操作就可以,得到这个字符串

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXN = 200000;
const int INF = 100000000;
struct node{
    node *p[26], *pre;
    int len, sons;
    node(){
        memset(p, 0, sizeof p);
        pre = NULL;
        len = 0; sons = 0;
    }
}Edges[MAXN*2+10], *ecnt=Edges+1,*root=Edges,*last=Edges, *st[MAXN*2+10];
void Insert(int w){
    node *np = ecnt++;
    node *p = last;
    np->len = p->len+1;
    while(p&&!p->p[w])
        p->p[w]=np, p=p->pre;
    if(!p){
        np->pre = root;
    }else{
        node *q = p->p[w];
        if(p->len+1 == q->len){
            np->pre = q;
        }else{
            node *nnd = ecnt++;
            memcpy(nnd->p, q->p, sizeof (nnd->p));
            nnd->len = p->len+1; nnd->pre = q->pre; q->pre = nnd; np->pre = nnd;
            while(p&&p->p[w]==q)
                p->p[w]=nnd, p=p->pre;
        }
    }
    last = np;
}
const int MAXT = 100000;
char s1[MAXT+10], s2[MAXT+10];
bool cmp(node *a, node *b){
    return a->len > b->len;
}
void Init(int ds){
    for(int i=0;i<ds;i++){
        st[i]->sons = 1;
        for(int j=0;j<26;j++)
            if(st[i]->p[j])
                st[i]->sons += st[i]->p[j]->sons;
    }
}
int main(){
    scanf("%s", s1);
    int l1 = strlen(s1), ans = 0;
    for(int i=0;i<l1;i++)
        Insert(s1[i]-'a');
    int ds = 0;
    for(node *p = &Edges[1];p!=ecnt;p++)
        st[ds++] = p;
    sort(st, st+ds, cmp);
    Init(ds);
    int q;
    scanf("%d", &q);
    for(int i=0;i<q;i++)
    {
        node *u = root;
        int k, tmp;
        scanf("%d", &k);
        while(k){
            for(int j=0;j<26;j++){
                if(u->p[j] && u->p[j]->sons < k) k -= u->p[j]->sons;
                else if(u->p[j]){
                    k--;
                    printf("%c", j+'a');
                    u = u->p[j];
                    break;
                }
            }
        }
        printf("\n");
    }

    return 0;
}

你可能感兴趣的:(后缀自动机)