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;
    }
    
  • 相关阅读:
    XML错误信息Referenced file contains errors (http://www.springframework.org/schema/beans/spring-beans-4.0.xsd). For more information, right click on the message in the Problems View ...
    Description Resource Path Location Type Cannot change version of project facet Dynamic Web Module to 2.3.
    maven创建web报错Cannot read lifecycle mapping metadata for artifact org.apache.maven.plugins:maven-compiler-plugin:maven-compiler-plugin:3.5.1:runtime Cause: error in opening zip file
    AJAX跨域
    JavaWeb学习总结(转载)
    JDBC学习笔记
    Java动态代理之JDK实现和CGlib实现
    (转)看懂UML类图
    spring boot配置使用fastjson
    python3下django连接mysql数据库
  • 原文地址:https://www.cnblogs.com/xiejiadong/p/6772967.html
Copyright © 2011-2022 走看看