【spoj SUBLEX】 Lexicographical Substring Search

http://www.spoj.com/problems/SUBLEX/ (题目链接)

题意

  给出一个字符串,询问其中字典序第K小的子串。

Solution

  后缀自动机例题。

  构出后缀自动机以后,对每个节点预处理出从这个节点可以到达多少个不同的子串。然后就是类似于在平衡树上查找一样沿着SAM一路查找下去一路更新答案了。

  代码借鉴的DaD3zZ大神,感觉好优美。

细节

  后缀自动机的节点数是2N的。

代码

// spoj7528
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=1000010;
char s[maxn],ans[maxn];
int n,K;

namespace SAM {
	int ch[maxn<<1][26],par[maxn<<1],len[maxn<<1],Dargen,last,sz;
	int b[maxn],id[maxn<<1],sum[maxn<<1];
	void Extend(int c) {
		int np=++sz,p=last;last=np;
		len[np]=len[p]+1;
		for (;p && !ch[p][c];p=par[p]) ch[p][c]=np;
		if (!p) par[np]=Dargen;
		else {
			int q=ch[p][c];
			if (len[p]+1==len[q]) par[np]=q;
			else {
				int nq=++sz;len[nq]=len[p]+1;
				memcpy(ch[nq],ch[q],sizeof(ch[nq]));
				par[nq]=par[q];
				par[np]=par[q]=nq;
				for (;p && ch[p][c]==q;p=par[p]) ch[p][c]=nq;
			}
		}
	}
	void build() {
		Dargen=last=sz=1;
		for (int i=1;i<=n;i++) Extend(s[i]-'a');
	}
	void pre() {   //貌似这个东西是精髓?一个O(n)的基数排序之后根据parent树的性质对Right集合的大小和一些其它奇奇怪怪的东西进行O(n)的预处理
		for (int i=1;i<=sz;i++) b[len[i]]++;
		for (int i=1;i<=n;i++) b[i]+=b[i-1];
		for (int i=1;i<=sz;i++) id[b[len[i]]--]=i;
		for (int i=sz,S=0;i>=1;i--,S=0) {   //sum记录当前节点不同子串个数
			for (int j=0;j<26;j++) S+=sum[ch[id[i]][j]];
			sum[id[i]]=S+1;
		}
	}
	void query(int K) {
		int now=Dargen,tot=0;
		while (K) {
			for (int i=0;i<26;i++) if (ch[now][i]) {
					if (sum[ch[now][i]]>=K) {
						ans[++tot]='a'+i,K--,now=ch[now][i];
						break;
					}
					else K-=sum[ch[now][i]];
				}
		}
		ans[++tot]='\0';
	}
}
using namespace SAM;

int main() {
	scanf("%s",s+1);
	n=strlen(s+1);
	build();
	pre();
	int q;scanf("%d",&q);
	while (q--) {
		scanf("%d",&K);
		query(K);
		puts(ans+1);
	}
    return 0;
}

 

posted @ 2017-01-15 19:46  MashiroSky  阅读(385)  评论(0编辑  收藏  举报