spoj SUBLEX - Lexicographical Substring Search【SAM】

先求出SAM,然后考虑定义,点u是一个right集合,代表了长为dis[son]+1~dis[u]的串,然后根据有向边转移是添加一个字符,所以可以根据这个预处理出si[u],表示串u后加字符能有几个本质不同子串
然后回答的时候在树上跑一下即可

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=300005;
int n,m,fa[N],ch[N][27],dis[N],si[N],con=1,cur=1,la,h[N],cnt,a[N],c[N];
char s[N];
struct qwe
{
	int ne,to;
}e[N<<2];
void add(int u,int v)
{
	cnt++;
	e[cnt].ne=h[u];
	e[cnt].to=v;
	h[u]=cnt;
}
void ins(int c,int id)
{
	la=cur,dis[cur=++con]=id;
	int p=la;
	for(;p&&!ch[p][c];p=fa[p])
		ch[p][c]=cur;
	if(!p)
		fa[cur]=1;
	else
	{
		int q=ch[p][c];
		if(dis[q]==dis[p]+1)
			fa[cur]=q;
		else
		{
			int nq=++con;
			dis[nq]=dis[p]+1;
			memcpy(ch[nq],ch[q],sizeof(ch[q]));
			fa[nq]=fa[q];
			fa[q]=fa[cur]=nq;
			for(;ch[p][c]==q;p=fa[p])
				ch[p][c]=nq;
		}
	}
}
void dfs(int u)
{
	for(int i=h[u];i;i=e[i].ne)
		dfs(e[i].to);
	for(int i=0;i<26;i++)
		si[u]+=si[ch[u][i]];
}
int main()
{
	scanf("%s%d",s+1,&m);
	n=strlen(s+1);
	for(int i=1;i<=n;i++)
		ins(s[i]-'a',i);
	for(int i=2;i<=con;i++)
		si[i]=1;
	// for(int i=2;i<=con;i++)
		// add(fa[i],i);
	// dfs(1);
	for(int i=1;i<=con;i++) 
		c[dis[i]]++;
    for(int i=1;i<=n;i++) 
		c[i]+=c[i-1];
    for(int i=1;i<=con;i++) 
		a[c[dis[i]]--]=i;
    for(int i=con;i;i--)
        for(int j=0;j<26;j++)
            si[a[i]]+=si[ch[a[i]][j]];
	while(m--)
    {
		int k;
        scanf("%d",&k);
        for(int p=1;k;)
        {
            if(p!=1) 
				k--;
            if(!k) 
				break;
            for(int i=0;i<26;i++)
                if(ch[p][i])
                {
                    if(k>si[ch[p][i]]) 
						k-=si[ch[p][i]];
                    else
                    {
                        printf("%c",i+'a');
                        p=ch[p][i];
                        break;
                    }
                }
        }
        puts("");
    }
}
posted @ 2018-11-23 07:57  lokiii  阅读(154)  评论(0编辑  收藏  举报