zoukankan      html  css  js  c++  java
  • 【模板题】后缀排序

    题目描述

    这是一道模板题。

    读入一个长度为 $n$ 的由小写英文字母组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 $1$ 到 $n$。

    除此之外为了进一步证明你确实有给后缀排序的超能力,请另外输出 $n - 1$ 个整数分别表示排序后相邻后缀的最长公共前缀的长度。

    输入格式

    一行一个长度为 $n$ 的仅包含小写英文字母的字符串。

    输出格式

    第一行 $n$ 个整数,第 $i$ 个整数表示排名为 $i$ 的后缀的第一个字符在原串中的位置。

    第二行 $n - 1$ 个整数,第 $i$ 个整数表示排名为 $i$ 和排名为 $i + 1$ 的后缀的最长公共前缀的长度。

    限制与约定

    $1 leq n leq 10^5$

    时间限制:$1 exttt{s}$

    空间限制:$256 exttt{MB}$


    似乎各种方法构造后缀数组都能跑过

    在Manchery大神的帮助下,终于理解了怎么从sam-->sa tree-->sa的完美转变

    首先,反串构造sam,那么他的par树,就是他的sa tree

    然后的问题就是怎么用后缀树线性构造后缀数组

    显然第一步是要把所有的fa边反向,指向孩子

    但直接处理有问题

    可以看一个样例

    aacca

    它对应的后缀树长这样(一下是吴老板的手稿)

    我们发现5、6节点都对应1节点,我们用trie树的方法来记录的话,5、6节点都是a开头的,显然有冲突

    于是,思考一种解决冲突的方法

    吴老板太神啦~!

    后面就是按照字典序来一遍dfs

    后面就是一些细节的问题了

    诸如复制节点的时候,要把对应的位置一起带过去,但要打上标记,以免dfs的sa数组中出现重复的编号

    那么,第二问的话,直接在par树上爬到lca即可,直接返回lca的len

    #include<cstdio>  
    #include<iostream>  
    #include<algorithm>  
    #include<cstdlib>  
    #include<cstring>
    #include<string>
    #include<climits>
    #include<vector>
    #include<cmath>
    #include<map>
    #define LL long long
     
    using namespace std;
     
    inline char nc(){
      static char buf[100000],*p1=buf,*p2=buf;
      if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
      return *p1++;
    }
     
    inline void read(int &x){
      char c=nc();int b=1;
      for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
      for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
    }
     
    inline void read(LL &x){
      char c=nc();LL b=1;
      for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
      for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
    }
    inline int read(char *s)
    {
        char c=nc();int len=0;
        for(;!((c>='A' && c<='Z')||(c>='a' && c<='z'));c=nc()) if (c==EOF) return 0;
        for(;((c>='A' && c<='Z')||(c>='a' && c<='z'));s[len++]=c,c=nc());
        s[len++]='';
        return len;
    }
    inline void read(char &x){
      for (x=nc();!(x=='?' || x=='+' || x=='-');x=nc());
    }
    int wt,ss[19];
    inline void print(int x){
        if (x<0) x=-x,putchar('-'); 
        if (!x) putchar(48); else {
        for (wt=0;x;ss[++wt]=x%10,x/=10);
        for (;wt;putchar(ss[wt]+48),wt--);}
    }
    inline void print(LL x){
        if (x<0) x=-x,putchar('-');
        if (!x) putchar(48); else {for (wt=0;x;ss[++wt]=x%10,x/=10);for (;wt;putchar(ss[wt]+48),wt--);}
    }
    int n,m,s,b[200010],c[200010],d[200010];
    char sx[200010],sy[200010];
    struct data
    {
        int len,fa,letter[26],tree[26],id,flag;
    }a[200010];
    int sa[200010],rank[200010],RANK;
    void Extend(int x,int p)
    {
        s++;int q=s;a[q].len=a[p].len+1;
        while (p!=0 && a[p].letter[x]==0)
            a[p].letter[x]=q,p=a[p].fa;
        if (p==0) {a[q].fa=1;return ;}
        int np=a[p].letter[x];
        if (a[np].len==a[p].len+1) a[q].fa=np;
        else
        {
            s++;int nq=s;a[nq].len=a[p].len+1;
            for (int i=0;i<26;i++)
                a[nq].letter[i]=a[np].letter[i];
            a[nq].id=a[np].id;
            a[nq].fa=a[np].fa;a[np].fa=nq;a[q].fa=nq;
            while (p!=0&&a[p].letter[x]==np)
                a[p].letter[x]=nq,p=a[p].fa;
        }
    }
    void Insert(char x[])
    {
        int y=strlen(x);
        s=1;int z=1;
        for (int i=y-1;i>=0;i--)
            Extend(x[i]-'a',z),z=a[z].letter[x[i]-'a'],a[z].id=i+1,d[i+1]=z,a[z].flag=1;
    }
    void dfs(int x)
    {
        if(a[x].id!=0 && a[x].flag) sa[++RANK]=a[x].id,rank[a[x].id]=RANK;
        for (int i=0;i<26;i++)
            if (a[x].tree[i]!=0) dfs(a[x].tree[i]);
    }
    void build()
    {
        for (int i=1;i<=s;i++)
            c[a[i].len]++;
        for (int i=1;i<=s;i++)
            c[i]+=c[i-1];
        for (int i=1;i<=s;i++)
            b[c[a[i].len]--]=i;
        for (int i=s;i>=1;i--)
        {
            int p=b[i];
            a[a[p].fa].tree[sx[a[p].id+a[a[p].fa].len-1]-'a']=p;
        }
        RANK=0;
        dfs(1);
    }
    LL Query(int x,int y)
    {
        if (x==y) return a[x].len;
        if (a[x].len>a[y].len) return Query(a[x].fa,y);
        else return Query(x,a[y].fa);
    }
    int main()
    {
        n=read(sx);n=strlen(sx);
        Insert(sx);
        build();
        for (int i=1;i<n;i++)
            print(sa[i]),putchar(' ');
        print(sa[n]);puts("");
        for (int i=1;i<n-1;i++)
            print(Query(d[sa[i]],d[sa[i+1]])),putchar(' ');
        if (n>1) print(Query(d[sa[n-1]],d[sa[n]])),puts("");
        return 0;
    }
    
  • 相关阅读:
    HDU
    C# Stopwatch
    RMQ(Range Minimum Query)问题(转)
    HDU
    POJ
    HDU
    POJ
    POJ
    docker安装testlink
    廖雪峰Java2面向对象编程-3继承和多态-2多态
  • 原文地址:https://www.cnblogs.com/xiejiadong/p/6772967.html
Copyright © 2011-2022 走看看