后缀数组模板 UOJ#35. 后缀排序

从梓轩学姐提交记录那里搞来的,简单易懂,没有那些奇奇怪怪的东西...

#include<cstdio>
#include<cstring>
const int MAXN=100000,D=50;
int n,str[MAXN+D];
int sa[MAXN+D],rank[MAXN+D],height[MAXN+D];
int p[MAXN+D],temp[MAXN+D],cnt[MAXN+D];
inline bool equ(int x,int y,int l){return rank[x]==rank[y]&&rank[x+l]==rank[y+l];}
void init(){
	char ch=getchar();
	while(ch>=‘a‘&&ch<=‘z‘)str[n++]=ch-‘a‘,ch=getchar();
}
void doubling()
{
	str[n]=rank[n]=-1;
	for(int i=0;i<n;i++)sa[i]=i,rank[i]=str[i];
	for(int i,l=0,pos=0,sig=26;pos<n-1;sig=pos)
	{
		for(i=n-l,pos=0;i<n;i++)p[pos++]=i;
		for(i=0;i<n;i++)if(sa[i]>=l)p[pos++]=sa[i]-l;
		memset(cnt,0,sizeof cnt);
		for(i=0;i<n;i++)cnt[rank[p[i]]]++;
		for(i=1;i<=sig;i++)cnt[i]+=cnt[i-1];
		for(i=n-1;i>=0;i--)sa[--cnt[rank[p[i]]]]=p[i];
		for(temp[sa[0]]=pos=0,i=1;i<n;i++)
		{
			if(!equ(sa[i],sa[i-1],l))pos++;
			temp[sa[i]]=pos;
		}
		for(i=0;i<n;i++)rank[i]=temp[i];
		if(!l)l=1;else l<<=1;
	}
}
void pre()
{
	int i,k;
	for(i=k=0;i<n;i++)
	{
		if(k)k--;
		if(rank[i]==0)continue;
		for(int j=sa[rank[i]-1];str[i+k]==str[j+k];)
			k++;
		height[rank[i]]=k;
	}
}
void print()
{
	for(int i=0;i<n;i++)
		printf("%d ",sa[i]+1);
	printf("\n");
	for(int i=1;i<n;i++)
		printf("%d ",height[i]);
}
int main(){
	init();
	if(n==1){printf("1");return 0;}
	doubling();
	pre();
	print();
	return 0;
}

  

原文地址:https://www.cnblogs.com/mybing/p/8481769.html

时间: 2024-07-29 20:21:34

后缀数组模板 UOJ#35. 后缀排序的相关文章

【后缀数组】uoj#35. 后缀排序

模板 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define N 100001 int sa[N],t[N],t2[N],tong[N],n; char s[N]; inline bool cmp(int *y,int i,int k) { return (y[sa[i-1]]==y[sa[i]])&&((sa[i-1]+k>=n?-1:

uoj #35. 后缀排序

这是一道模板题. 读入一个长度为 n n 的由小写英文字母组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置.位置编号为 1 1 到 n n. 除此之外为了进一步证明你确实有给后缀排序的超能力,请另外输出 n?1 n?1 个整数分别表示排序后相邻后缀的最长公共前缀的长度. 输入格式 一行一个长度为 n n 的仅包含小写英文字母的字符串. 输出格式 第一行 n n 个整数,第 i i 个整数表示排名为 i i 的后缀的第一个字符在原串中的位

后缀数组模板第一版

/*---------------倍增算法+RMQ后缀数组模板-------------- 输入:从0开始的字符串g,长度len最大为10^6 输出: sa[]表示:n 个后缀从小到大进行排序之后把排好序的后缀的开头位置顺 次放入 sa 中,sa[i]表示排第i位的字符串开头是sa[i],因为添加了一个结尾0,所以sa[0]=len height 数组(h[]):定义 h[i]=suffix(sa[i-1])和 suffix(sa[i])的最长公 共前缀,也就是排名相邻的两个后缀的最长公共前缀.

后缀数组模板一份

1 /****************** 2     by zhuyuqi      * 3     QQ:1113865149 * 4     name:2-sat    * 5                   * 6 ******************/ 7  8 using namespace std; 9 const int MAX = 1000;10 int r[MAX],*rank;11 int wa[MAX],wb[MAX],ws[MAX],wv[MAX];12 int h

后缀数组模板/LCP模板

1 //后缀数组模板,MANX为数组的大小 2 //支持的操作有计算后缀数组(sa数组), 计算相邻两元素的最长公共前缀(height数组),使用get_height(); 3 //计算两个后缀a, 和b的最长公共前缀,请先使用lcp_init(),再调用get_lcp(a, b)得到 4 //下面的n是输入字符串的长度+1(n = strlen(s) + 1), m是模板的范围 m=128表示在字母,数字范围内,可以扩大也可缩小 5 //s[len] 是插入的一个比输入字符都要小的字符 6 s

[UOJ#35] [UOJ后缀数组模板题] 后缀排序 [后缀数组模板]

后缀数组,解决字符串问题的有利工具,本题代码为倍增SA算法 具体解释详见2009年国家集训队论文 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cmath> 7 #include <ctime> 8 9 using namespace

后缀数组模板及解释

以前做过后缀数组,直接用模板,最近打算重新认真的学一遍.感觉学一个东西一定要弄懂了,不然到最后还是要重学. int wa[MAXN],wb[MAXN],wv[MAXN],Ws[MAXN]; void da(int *r,int *sa,int n,int m){//n表示字符串长度 + 1,包括添加的那个0,m表示取值的范围 //把单个字符进行基数排序 int *x = wa,*y = wb; for(int i = 0; i < m; i++)Ws[i] = 0; for(int i = 0;

hdu1403(后缀数组模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403 题意: 给出两个字符串, 求他们的最长公共子串 思路: 两个字符串的最长公共子串长度显然就是两个字符串的所有后缀中的最长公共前缀长度. 可以先用一个没有出现的字符(便于后面区分后缀是否属于相同字符串)将两个字符串连成一个字符串,再用后缀数组求其height, SA数组, 对于当前 i, 通过 SA 数组区分后缀 i 和 i - 1 是否在同一个初始字符串中, 若不是则用 height[i] 维

后缀数组模板(理解)

字符串的处理真可谓是博大精深,后缀数组这种数据结构我花了两天时间才明白了其构造的过程.主要是代码不好理解. 数据结构: 1.sa数组,就是后缀数组,按照字典序排列,其意义为:sa[i]=k,排第i名的子串是从k位开始的. 2.rank名次数组,其意义为:rank[i]=k,以i为起点的子串排名为k. 很容易看出来两者可以相互转化. 求这两个数组的过程是基于基数排序,计数排序的方法. 下面是一个大牛的注释版.其中我在补充点: 1.对于求y[]这个数组,因为已经知道上次长为j的子串比较结果,那么这次