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

传送门

解题思路

  首先建\(sam\),然后在拓扑序上\(dp\)一下,把每个点的路径数算出来,然后统计答案时就在自动机上\(dfs\)一下,仿照平衡树那样找第\(k\)小。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>

using namespace std;
const int MAXN = 90005;

inline int rd(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return f?x:-x;
}

int n,Q,l[MAXN<<1],fa[MAXN<<1],ch[MAXN<<1][27];
int lst,cnt,f[MAXN<<1],c[MAXN<<1],a[MAXN<<1];
char s[MAXN];

inline void Insert(int c){
	int p=lst,np=++cnt;lst=np;l[np]=l[p]+1;
	for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
	if(!p) fa[np]=1;
	else {
		int q=ch[p][c];
		if(l[q]==l[p]+1) fa[np]=q;
		else{
			int nq=++cnt;l[nq]=l[p]+1;
			memcpy(ch[nq],ch[q],sizeof(ch[q]));
			fa[nq]=fa[q];fa[q]=fa[np]=nq;
			for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
		}
	}
} 

void query(int x){
	int p=1;
	while(x){
		for(int i=1;i<=26;i++)if(ch[p][i]){
			if(f[ch[p][i]]<x)  x-=f[ch[p][i]];
			else {p=ch[p][i];putchar('a'+i-1);x--;break;}	
		}
	}
	putchar('\n');
}

int main(){
	scanf("%s",s+1);n=strlen(s+1);lst=cnt=1;
	for(int i=1;i<=n;i++) Insert(s[i]-'a'+1);
	for(int i=1;i<=cnt;i++) c[l[i]]++;
	for(int i=1;i<=cnt;i++) c[i]+=c[i-1];
	for(int i=1;i<=cnt;i++) a[c[l[i]]--]=i;
	for(int i=cnt;i;i--){
		f[a[i]]=1;
		for(int j=1;j<=26;j++)
			f[a[i]]+=f[ch[a[i]][j]];
	}
	f[1]--;Q=rd();int x;
	while(Q--){x=rd();query(x);}
	return 0;
} 
posted @ 2018-12-11 23:59  Monster_Qi  阅读(149)  评论(0编辑  收藏  举报