【模板题】后缀排序
2017-04-27 10:35
399 查看
题目描述
这是一道模板题。
读入一个长度为 $n$ 的由小写英文字母组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 $1$ 到 $n$。
除此之外为了进一步证明你确实有给后缀排序的超能力,请另外输出 $n - 1$ 个整数分别表示排序后相邻后缀的最长公共前缀的长度。
输入格式
一行一个长度为 $n$ 的仅包含小写英文字母的字符串。
输出格式
第一行 $n$ 个整数,第 $i$ 个整数表示排名为 $i$ 的后缀的第一个字符在原串中的位置。
第二行 $n - 1$ 个整数,第 $i$ 个整数表示排名为 $i$ 和排名为 $i + 1$ 的后缀的最长公共前缀的长度。
限制与约定
$1 \leq n \leq 10^5$
时间限制:$1\texttt{s}$
空间限制:$256\texttt{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++]='\0'; 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 );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 ])),puts(""); return 0; }
相关文章推荐
- 洛谷P3809 【模板】后缀排序
- [洛谷P3809]【模板】后缀排序
- UOJ #35. BZOJ 1031 后缀排序 后缀数组模板
- luogu #3809 【模板】后缀排序(后缀数组)
- luogu P3809 【模板】后缀排序
- UOJ #35. 后缀排序(后缀数组模板题)
- UOJ.35.[模板]后缀排序(后缀数组 倍增)
- luogu P3809 【模板】后缀排序
- P3809 【模板】后缀排序
- 洛谷.3809.[模板]后缀排序(后缀数组 倍增)
- UOJ #35. 后缀排序 后缀数组模板题
- 【UOJ #35】后缀排序 后缀数组模板
- 后缀自动机(SAM)模板
- [最小循环表示 后缀自动机 模板题] BZOJ 2882 工艺
- 排序模板(从小到大)
- 后缀自动机 模板
- node.js 使用ejs模板引擎时后缀换成.html
- 后缀子串排序
- 用模板写选择排序-数组
- SPOJ 8222. Substrings(后缀自动机模板)