2018.12.15【UOJ35】字尾排序(各種做法(包括SAM))
阿新 • • 發佈:2018-12-17
傳送門
解析:
SAM以外的其他做法:https://blog.csdn.net/zxyoi_dreamer/article/details/84667881
SAM做法:
在反串上建出SAM,標記每一個反串的字首終止位置(即原串的字尾起始位置),保留fail樹。
留下來的fail樹就是原串的字尾樹。
在後綴樹上按照字典序進行DFS將遇到的標記一一收回,就完成了字尾陣列的構建。
沒聽懂?回去學習字尾樹
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
cs int N=100005;
namespace SA{
char s[N];
int sa[N],rk[N],ht[N],len,cnt;
typedef struct SAM_node *point;
struct SAM_node{
int len,pos;bool tag;
point fa,son[26],trans[26];
SAM_node():len(0),pos(0),tag(0),fa(NULL){memset (son,0,sizeof son);}
};
namespace SAM{
SAM_node nd[N<<1];
point now(nd),last(nd);
inline void push_back(char c,int pos){
c-='a';
point cur=++now;
cur->len=last->len+1;
cur->tag=true;
cur->pos=pos;
point p=last;
for(;p&&!p->son[c];p=p->fa)p- >son[c]=cur;
if(!p)cur->fa=nd;
else if(p->son[c]->len==p->len+1)cur->fa=p->son[c];
else {
point clone=++now,q=p->son[c];
*clone=*q;
clone->len=p->len+1;
clone->tag=false;
q->fa=cur->fa=clone;
for(;p&&p->son[c]==q;p=p->fa)p->son[c]=clone;
}
last=cur;
}
};
inline void dfs(point now){
if(now->tag)sa[rk[now->pos]=++cnt]=now->pos;
for(int re i=0;i<26;++i)
if(now->trans[i])dfs(now->trans[i]);
}
inline void init(){
for(int re i=len;i;--i)SAM::push_back(s[i],i);
for(point re i=SAM::nd+1;i<=SAM::now;++i)i->fa->trans[s[i->pos+i->fa->len]-'a']=i;
dfs(SAM::nd);
for(int re i=1,k=0,j;i<=len;ht[rk[i++]]=k)
for(k?--k:0,j=sa[rk[i]-1];s[i+k]==s[j+k];++k);
}
}
signed main(){
scanf("%s",SA::s+1);
SA::len=strlen(SA::s+1);
SA::s[SA::len+1]='\0';
SA::init();
for(int re i=1;i<=SA::len;++i)printf("%d ",SA::sa[i]);pc('\n');
for(int re i=2;i<=SA::len;++i)printf("%d ",SA::ht[i]);pc('\n');
return 0;
}