后缀排序

题目描述

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

输入输出格式

输入格式:

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

输出格式:

一行,共n个整数,表示答案。

输入输出样例

输入样例#1:
复制

ababa
输出样例#1:
复制

5 3 1 4 2

说明

$n <= 10^6$

题解

推荐博客:算法学习:后缀自动机转后缀树转后缀数组

对反串建立后缀自动机,然后用parent树建出后缀树,最后在后缀树上dfs求出后缀数组。

因为后缀自动机的parent树连起来是原串的反向前缀树,所以对反串这样做建立起的就是后缀树。

对反串建立后缀自动机的时候,要额外记录pos数组,表示节点对应的原串中后缀起始位置。这样配合len数组便知道了后缀树上面的边上面的字符。

时间复杂度\(O(n)\)


字符集包含大小写英文字母或数字,这就非常烦了……用了各种奇技淫巧才卡过这道题。

co int N=2e6+10;
char s[N];
int n;
// SAM
unordered_map<int,int> ch[N];
int pos[N],val[N],len[N],fa[N],last=1,sz=1;
void extend(int c,int po){
int p=last,cur=last=++sz;
pos[cur]=po,val[cur]=1,len[cur]=len[p]+1;
for(;p&&!ch[p].count(c);p=fa[p]) ch[p][c]=cur;
if(!p) fa[cur]=1;
else{
int q=ch[p][c];
if(len[q]==len[p]+1) fa[cur]=q;
else{
int clone=++sz;len[clone]=len[p]+1;
ch[clone]=ch[q];
fa[clone]=fa[q],pos[clone]=pos[q];
fa[q]=fa[cur]=clone;
for(;ch[p].count(c)&&ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
}
}
}
// ST
vector<pair<int,int> > e[N];
int sa[N],rank[N],tp;
void dfs(int u){
if(val[u]) sa[::rank[pos[u]]=++tp]=pos[u];
sort(e[u].begin(),e[u].end());
for(auto i:e[u]) dfs(i.second);
}
int main(){
scanf("%s",s+1),n=strlen(s+1);
for(int i=n;i>=1;--i) extend(s[i],i);
for(int i=2;i<=sz;++i) e[fa[i]].push_back(make_pair(s[pos[i]+len[fa[i]]],i));
dfs(1);
for(int i=1;i<=n;++i) printf("%d ",sa[i]);
return 0;
}

LG3809 【模板】后缀排序的更多相关文章

  1. 洛谷.3809.[模板]后缀排序(后缀数组 倍增) & 学习笔记

    题目链接 //输出ht见UOJ.35 #include<cstdio> #include<cstring> #include<algorithm> const in ...

  2. UOJ.35.[模板]后缀排序(后缀数组 倍增)

    题目链接 论找到一个好的教程的正确性.. 后缀数组 下标从1编号: //299ms 2560kb #include <cstdio> #include <cstring> #i ...

  3. P3809 【模板】后缀排序

    P3809 [模板]后缀排序 从这学的 后缀数组sa[i]就表示排名为i的后缀的起始位置 x[i]是第i个元素的第一关键字 y[i]表示第二关键字排名为i的数,在第一关键字中的位置 #include& ...

  4. 洛谷:P3809 【模板】后缀排序(后缀数组模板)

    P3809 [模板]后缀排序 题目链接:https://www.luogu.org/problemnew/show/P3809 题目背景 这是一道模板题. 题目描述 读入一个长度为 nn 的由大小写英 ...

  5. [洛谷P3809]【模板】后缀排序

    [洛谷P3809][模板]后缀排序 题目大意: 对于给定的长度为\(n(n\le10^6)\)的字符串求后缀数组\(sa[i]\). 思路: 倍增+快排构造后缀数组.代码参考<挑战程序设计竞赛& ...

  6. 【模板】后缀排序(SA数组)

    [模板]后缀排序 题目背景 这是一道模板题. 题目描述 读入一个长度为 \(n\) 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字 ...

  7. codevs1500 后缀排序

    题目描述 Description 天凯是MIT的新生.Prof. HandsomeG给了他一个长度为n的由小写字母构成的字符串,要求他把该字符串的n个后缀(suffix)从小到大排序. 何谓后缀?假设 ...

  8. UOJ#35 后缀排序

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

  9. 2018.11.24 loj#111. 后缀排序(后缀数组)

    传送门 后缀排序模板题. 终于会后缀数组了(然而只会倍增并不会DC3DC3DC3). 在这里列举几个数组的意思: sai:sa_i:sai​:当前排名第iii的后缀的起始下标. rkirk_irki​ ...

随机推荐

  1. Java 整体测试重点题 错题积累

    重点题    错题积累 1: 解析: %d:用来设置输出日志的日期和时间 %m:用来输出代码中指定的消息 %n:用来输出一个回车换行符 %l:用来输出日志事件的发生位置 %p:用来输出优先级 %f:用 ...

  2. node连接myslq

    var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : ' ...

  3. Mysql使用information.shema.tables查询数据库表大小

    简介: information_schema数据库中的表都是只读的,不能进行更新.删除和插入等操作,也不能加触发器,因为它们实际只是一个视图,不是基本表,没有关联的文件. 元数据描述数据的数据,用于描 ...

  4. Linux alias别名命令

    首先介绍一下命令的别名,怎么查看的呢? 咱们使用which命令就可以查看的到它完整的命令是怎样的 [root@master ~]# which ls alias ls='ls --color=auto ...

  5. Bootstrap中模态框多层嵌套时滚动条问题

    在使用Bootstrap中模态框过程中,如果出现多层嵌套的时候,如打开模态框A,然后在A中打开模态框B,在关闭B之后,如果A的内容比较多,滚动条会消失,而变为Body的滚动条,这是由于模态框自带的遮罩 ...

  6. Oracle特殊字符转义:&amp;和&#39;

    Oracle特殊字符转义:&和'    我们在SQL*PLUS下执行 SQL show all命令时,可以发现一个参数:define & (hex 26),如下所示 concat . ...

  7. mysql 数据库关于增加用户权限的问题

    一新建用户 ----------- 二首先修改权限必须在电脑cmd 中运行 开设的权限  主要就是 1 所有库的  *.*      2  所有的表   db.*      3所有的字段db.t1   ...

  8. 如何实时查看Linux下日志

    以下以Tomcat为例子,其他WEB服务器目录自己灵活修改即可: 1.先切换到:cd usr/local/tomcat5/logs2.tail -f catalina.out3.这样运行时就可以实时查 ...

  9. linux 基本命令大全

    系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...

  10. [转]Deep Reinforcement Learning Based Trading Application at JP Morgan Chase

    Deep Reinforcement Learning Based Trading Application at JP Morgan Chase https://medium.com/@ranko.m ...