SP7258 SUBLEX - Lexicographical Substring Search

题意:给定一个字符串,求本质不同排名第k小的子串。

\(SAM\)

建好 \(SAM\) 后,拓扑排序求出每个点向下的子串数,然后在 \(trie\) 树上贪心(类似线段树二分)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=180010;
int T,k,lst=1,tot=1,cnt;
int len[N],fa[N],c[N][26];
char s[N>>1];
int f[N],d[N],mem[N];
inline void add(int ch) {
  R p=lst,np=lst=++tot;
  len[np]=len[p]+1;
  for(;p&&!c[p][ch];p=fa[p]) c[p][ch]=np;
  if(!p) fa[np]=1;
  else {
    R q=c[p][ch];
    if(len[q]==len[p]+1) fa[np]=q;
    else {
      R nq=++tot;
      memcpy(c[nq],c[q],26<<2);
      fa[nq]=fa[q],len[nq]=len[p]+1;
      fa[np]=fa[q]=nq;
      for(;p&&c[p][ch]==q;p=fa[p]) c[p][ch]=nq;
    }
  }
}
inline void solve() {
  R p=1;  
  while(k) {
    for(R i=0;i<26;++i) {
      if(!c[p][i]) continue;
      if(f[c[p][i]]<k) k-=f[c[p][i]];
      else {
        putchar(i+'a');
        p=c[p][i];
        --k; break;
      } 
    }
  } putchar(10);
}
queue<int> q;
inline void main() {
  scanf("%s",s),k=strlen(s),T=g();
  for(R i=0;i<k;++i) add(s[i]-'a');
  for(R i=1;i<=tot;++i) ++d[len[i]];
  for(R i=1;i<=k;++i) d[i]+=d[i-1];
  for(R i=1;i<=tot;++i) mem[d[len[i]]--]=i;
  for(R i=tot;i;--i) {
    f[mem[i]]=1;
    for(R j=0;j<26;++j) if(c[mem[i]][j])
      f[mem[i]]+=f[c[mem[i]][j]];
  }
  while(T--) k=g(),solve();
}
} signed main() {Luitaryi::main(); return 0;}

2020.01.09

posted @ 2020-01-10 17:45  LuitaryiJack  阅读(89)  评论(0编辑  收藏  举报