【sam复习】用sam实现后缀排序

没错,一定是无聊到一定境界的人才能干出这种事情。

这个无聊的zcysky已经不满足于用后缀平衡树求sa了,他想用sam试试。

我们回顾下sam的插入过程,如果我们从最后一个state沿着suffix link向上爬parent tree

那么我们就可以遍历这个sam的所有后缀。

那么我们把插入的时候经历的state全都标记下来,并且记录下这个state对应的序号

在对parent tree进行dfs的时候先序遍历一下就可以了。

#include<bits/stdc++.h>
#define N 300010
using namespace std;
int n,c[N],tot,tota,sacnt,top=0,cnt=0;
int last=1,fa[N],ch[N][26],l[N],vis[N],head[N];
int r[N],sa[N],rk[N],h[N];
char s[N];
struct state{int x,y,v;}q[N];
struct Edge{int u,v,next;}G[N<<1];
inline void addedge(int u,int v){
    G[++tot].u=u;G[tot].v=v;G[tot].next=head[u];head[u]=tot;
}
void dfs(int u){
    if(r[u])sa[++sacnt]=r[u];
    for(int i=head[u];i;i=G[i].next)dfs(G[i].v);
}
void ins(int c,int pos){
    int p=last,np=++cnt;last=np;l[np]=l[p]+1;r[np]=pos;
    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[p]+1==l[q])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[np]=fa[q]=nq;
            for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
        }
    }
}
int main(){
    int f=0;
    scanf("%s",s+1);n=strlen(s+1);
    vis[1]=last=cnt=1;
    for(int i=n;i;i--)ins(s[i]-'a',i);
    for(int i=1;i<=cnt;i++)if(r[i]&&!vis[i])
    for(int pos=n,j=i;!vis[j];vis[j]=1,j=fa[j],--pos){
        pos=pos-l[j]+l[fa[j]]+1;q[++top]=(state){fa[j],j,s[pos]-'a'};
    }
    for(int i=1;i<=top;i++)c[q[i].v]++;
    for(int i=1;i<26;i++)c[i]+=c[i-1];
    for(int i=top;i;i--)rk[c[q[i].v]--]=i;
    for(;top;top--)addedge(q[rk[top]].x,q[rk[top]].y);
    dfs(1);
    for(int i=1;i<=n;i++)printf("%d ",sa[i]);puts("");
    for(int i=1;i<=n;i++)rk[sa[i]]=i;
    for(int i=1;i<=n;i++){
        int f=max(h[rk[i-1]]-1,0);    
        for(int j=sa[rk[i]-1];s[i+f]==s[j+f];f++);
        h[rk[i]]=f;
    }
    for(int i=2;i<=n;i++)printf("%d ",h[i]);
}

 

就这样,用sam就把这题水过去了~

posted @ 2017-06-22 16:30  zcysky  阅读(993)  评论(0编辑  收藏  举报