后缀自动机构建后缀数组

@(XSY)[后缀自动机, 后缀数组, 后缀树]
事实上构建后缀数组完全没有必要这么麻烦...
但作为对后缀自动机/后缀树的初步熟悉, 写一写还是很有必要的...
明明是线性构造, 为什么跑得比\(O(n \log n)\)倍增的还要慢...

#include <cstdio>
#include <cstring>

const int LEN = (int)5e4;
char str[LEN];

struct suffixTree
{
	int rk[LEN], SA[LEN], ht[LEN];

	struct node
	{
		int suc[26], pos, isRl;

		inline node()
		{
			memset(suc, -1, sizeof(suc));
		}
	}nd[LEN << 1];

	inline void addEdge(int u, int v, int c)
	{
		nd[u].suc[c] = v;
	}

	int cnt;

	inline void DFS(int u)
	{
		if(nd[u].isRl)
			rk[nd[u].pos] = cnt, SA[cnt ++] = nd[u].pos;

		for(int i = 0; i < 26; ++ i)
			if(~ nd[u].suc[i])
				DFS(nd[u].suc[i]);
	}

	inline void getAnswer()
	{
		cnt = 0;
		DFS(0);

		for(int i = 0; i < cnt; ++ i)
			printf("%d ", rk[i] + 1);
		
		puts("");
		
		ht[0] = 0;
    	int p = 0;
		
		for(int i = 0; i < cnt; ++ i)
			if(rk[i])
			{	
				for(p ? -- p : p ; i + p < cnt && SA[rk[i] - 1] + p < cnt && str[i + p] == str[SA[rk[i] - 1] + p]; ++ p);
				
				ht[rk[i]] = p;
			}
		
		for(int i = 0; i < cnt; ++ i)
			printf("%d ", ht[i]);
	}
}tr;

struct suffixAutomaton
{
	int s, lst, tp;

	struct state
	{
		int suc[26], pre, dis, pos, isRl;

		inline state()
		{
			memset(suc, -1, sizeof(suc));
			pre = pos = -1, dis = isRl = 0;
		}
	}nd[LEN << 1];

	inline void initialize()
	{
		s = lst = 0;
		tp = 1;
	}

	inline void insert(int c, int pos)
	{
		int pre = lst, u = tp ++;
		nd[u].pos = pos, nd[u].dis = nd[pre].dis + 1, nd[u].isRl = 1;

		for(; ~ pre && nd[pre].suc[c] == -1; pre = nd[pre].pre)
			nd[pre].suc[c] = u;

		if(pre == -1)
			nd[u].pre = s;
		else
		{
			int preSuc = nd[pre].suc[c];

			if(nd[preSuc].dis == nd[pre].dis + 1)
				nd[u].pre = preSuc;
			else
			{
				int v = tp ++;
				nd[v] = nd[preSuc];
				nd[v].dis = nd[pre].dis + 1, nd[v].isRl = 0;
				nd[preSuc].pre = nd[u].pre = v;

				for(; ~ pre && nd[pre].suc[c] == preSuc; pre = nd[pre].pre)
					nd[pre].suc[c] = v;
			}
		}

		lst = u;
	}

	inline void buildSuffixTree(char *str)
	{
		for(int i = 0; i < tp; ++ i)
			tr.nd[i].isRl = nd[i].isRl, tr.nd[i].pos = nd[i].pos;
		
		for(int i = 0; i < tp; ++ i)
			if(~ nd[i].pre)
				tr.addEdge(nd[i].pre, i, (int)str[nd[i].pos + nd[nd[i].pre].dis] - 'a');
	}
}SAM;

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("suffixSort.in", "r", stdin);
	freopen("suffixSort.out", "w", stdout);
	#endif
	
	gets(str);
	int len = strlen(str);
	SAM.initialize();

	for(int i = len - 1; ~ i; -- i)
		SAM.insert((int)str[i] - 'a', i);

	SAM.buildSuffixTree(str);
	tr.getAnswer();
}
posted @ 2017-04-16 08:35  Zeonfai  阅读(803)  评论(4编辑  收藏  举报