Lexicographical Substring Search SPOJ - SUBLEX (后缀自动机)

Lexicographical Substrings Search

\[Time Limit: 149 ms \quad Memory Limit: 1572864 kB \]

题意

给出一个字符串,求出这个字符串上字典序第 \(k\) 小的子串。

思路

先对给出的字符串构建后缀自动机,因为后缀自动机上从根节点走到任意节点都是原串的一个子串,所以我们可以 \(dfs\) 求出节点 \(i\) 往后存在多少个子串。
对于查询第 \(k\) 小的子串时,在用一个 \(dfs\) 来求,对于当前节点\(u\), 从\(1-26\) 枚举下一步的方案 \(v\),如果从 \(v\) 往后的子串比 \(k\) 少,那么不用往下走,直接 \(k-=cnt[v]\)。否则往下走一步,让 \(k--\)。如此一直走到 \(k=0\) 为止。

/***************************************************************
    > File Name    : a.cpp
    > Author       : Jiaaaaaaaqi
    > Created Time : 2019年05月22日 星期三 17时06分12秒
 ***************************************************************/

#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pii        pair<int, int>

typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 1e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m;
int cas, tol, T;

struct SAM {
	struct Node{
		int next[27];
		int fa, len;
		void init() {
			mes(next, 0);
			len = fa = 0;
		}
	} node[maxn<<1];
	int sz, last;
	int cnt[maxn<<1];
	void init() {
		sz = last = 1;
		node[sz].init();
		mes(cnt, 0);
	}
	void insert(int k) {
		int p = last, np = last = ++sz;
		node[np].init();
		node[np].len = node[p].len+1;
		for(; p&&!node[p].next[k]; p=node[p].fa)
			node[p].next[k] = np;
		if(p==0) {
			node[np].fa = 1;
		} else {
			int q = node[p].next[k];
			if(node[q].len == node[p].len + 1) {
				node[np].fa = q;
			} else {
				int nq = ++sz;
				node[nq] = node[q];
				node[nq].len = node[p].len + 1;
				node[np].fa = node[q].fa = nq;
				for(; p&&node[p].next[k]==q; p=node[p].fa)
					node[p].next[k] = nq;
			}
		}
	}
	void dfs(int u) {
		if(cnt[u])	return ;
		cnt[u] = 1;
		for(int i=1; i<=26; i++) {
			int v = node[u].next[i];
			if(v) {
				dfs(v);
				cnt[u] += cnt[v];
			}
		}
	}
	char ss[maxn];
	void find(int u, int k, int len) {
		if(k==0) {
			ss[len] = '\0';
			printf("%s\n", ss+1);
			return ;
		}
		for(int i=1; i<=26; i++) {
			int v = node[u].next[i];
			if(v==0)	continue;
			if(cnt[v] < k)	k -= cnt[v];
			else {
				k--;
				ss[len] = 'a'+i-1;
				find(v, k, len+1);
				return ;
			}
		}
	}
	void solve(int k) {
		find(1, k, 1);
	}
} sam;
char s[maxn];

int main() {
	sam.init();
	scanf("%s", s+1);
	int len = strlen(s+1);
	for(int i=1; i<=len; i++) {
		sam.insert(s[i]-'a'+1);
	}
	sam.dfs(1);
	// for(int i=2; i<=sam.sz; i++) {
	//     printf("cnt[%d] = %d\n", i, sam.cnt[i]);
	// }
	scanf("%d", &T);
	while(T--) {
		scanf("%d", &m);
		sam.solve(m);
	}
	return 0;
}
posted @ 2019-05-22 18:15  Jiaaaaaaaqi  阅读(186)  评论(0编辑  收藏  举报