zoukankan      html  css  js  c++  java
  • 后缀自动机构建后缀数组

    @(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();
    }
    
  • 相关阅读:
    生成按月递增循环日期
    js判断上传图片宽高及文件大小
    网页上如何实现禁止复制粘贴以及如何破解
    PAT(乙级)1019
    PAT(乙级)1018
    PAT(乙级)1017
    PAT(乙级)1016
    PAT(乙级)1015
    关于PAT(乙级)
    PAT(乙级)1014
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6717651.html
Copyright © 2011-2022 走看看