SPOJ SUBLEX

SUBLEX - Lexicographical Substring Search

链接

题意

  求第k小的子串。相同的算一个。

 

分析

  建立后缀自动机,在后缀自动机上从一个点经过trans,到另一个点,trans会对应一个子串。而且会对应所有的子串。

  每个节点能经过trans到达的点,即它可以形成的子串。所有按照拓扑序更新每个节点能形成多少个子串,如果经过当前点形成的串小于k,那么说明第k小的串不经过高这个点,k-=siz,继续找,如果小于这个的siz,那么就经过这个点,输出。有点像二叉搜索树的查询。

 

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 
 5 inline int read() {
 6     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
 7     for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
 8 }
 9 
10 const int N = 200100;
11 
12 struct SuffixAutomaton{
13     int Last, Index, fa[N], len[N], trans[N][26];
14     int v[N],sa[N],siz[N];
15     char s[N];
16     void extend(int c) {
17         int P = Last, NP = ++Index;
18         len[NP] = len[P] + 1;
19         for (; P&&!trans[P][c]; P=fa[P]) trans[P][c] = NP;
20         if (!P) fa[NP] = 1;
21         else {
22             int Q = trans[P][c];
23             if (len[P] + 1 == len[Q]) fa[NP] = Q;
24             else {
25                 int NQ = ++Index;
26                 fa[NQ] = fa[Q];
27                 len[NQ] = len[P] + 1;
28                 memcpy(trans[NQ], trans[Q], sizeof trans[Q]);
29                 fa[Q] = NQ;
30                 fa[NP] = NQ;
31                 for (; P&&trans[P][c]==Q; P=fa[P]) trans[P][c] = NQ;
32             }
33         }
34         Last = NP;
35     }
36     void build() {
37         Last = Index = 1; //---老是忘记这里。。。 
38         scanf("%s",s+1);
39         int n = strlen(s+1);
40         for (int i=1; i<=n; ++i) extend(s[i] - 'a');
41         for (int i=1; i<=Index; ++i) v[len[i]] ++;
42         for (int i=1; i<=n; ++i) v[i] += v[i-1];
43         for (int i=1; i<=Index; ++i) sa[ v[len[i]]-- ] = i;
44     }
45     
46     void init() {
47         for (int i=Index; i>=1; --i) {
48             int t = sa[i];
49             siz[t] ++;
50             for (int j=0; j<26; ++j) {
51                 if (trans[t][j]) siz[t] += siz[trans[t][j]];
52             }
53         }
54     }
55     void query(int k) {
56         int p = 1;
57         while (k) 
58             for (int i=0; i<26; ++i) 
59                 if (trans[p][i]) 
60                     if (k > siz[trans[p][i]]) k -= siz[trans[p][i]];
61                     else {
62                         printf("%c",i+'a');
63                         p = trans[p][i];
64                         k--;
65                         break;
66                     }
67     }
68     void solve() {
69         build();
70         init();
71         int m = read(),k;
72         while (m--) {
73             k = read();
74             query(k);
75             puts("");
76         }
77     }
78 }sam;
79 
80 int main() {
81     sam.solve();
82     return 0;
83 }

 

posted @ 2018-07-19 17:31  MJT12044  阅读(340)  评论(0编辑  收藏  举报