1. 程式人生 > >2018.12.15【UOJ35】字尾排序(各種做法(包括SAM))

2018.12.15【UOJ35】字尾排序(各種做法(包括SAM))

傳送門


解析:

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; }