zoukankan      html  css  js  c++  java
  • LG P3809 【模板】后缀排序

    贴模板

    注意:( ext{id}) 表示第二关键字排序后(其实无需排序,利用上轮的 ( ext{sa}) 值即可)相应的第一关键字的位置
    计数排序为了稳定性最后确定位置时要倒着开始
    复制的 ( ext{ork}) 要开两倍

    ( ext{Code})

    #include <cstdio>
    #include <cstring>
    #define re register
    using namespace std;
    
    const int N = 1e6 + 5;
    int n, sa[N], rk[N], cnt[N], id[N], ork[N << 1];
    char s[N];
    
    inline int comp(int x, int y, int w){return (ork[x] == ork[y]) && (ork[x + w] == ork[y + w]);}
    
    inline void build_SA()
    {
    	int m = 300, p;
    	for(re int i = 1; i <= n; i++) ++cnt[rk[i] = s[i]];
    	for(re int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
    	for(re int i = n; i; i--) sa[cnt[rk[i]]--] = i;
    	
    	for(re int w = 1; w < n; w <<= 1, m = p)
    	{
    		p = 0;
    		for(re int i = n - w + 1; i <= n; i++) id[++p] = i;
    		for(re int i = 1; i <= n; i++)
    		if (sa[i] > w) id[++p] = sa[i] - w;
    		
    		for(re int i = 0; i <= m; i++) cnt[i] = 0;
    		for(re int i = 1; i <= n; i++) ++cnt[rk[id[i]]];
    		for(re int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
    		for(re int i = n; i; i--) sa[cnt[rk[id[i]]]--] = id[i];
    		
    		for(re int i = 1; i <= n; i++) ork[i] = rk[i];
    		p = 0;
    		for(re int i = 1; i <= n; i++)
    		rk[sa[i]] = comp(sa[i], sa[i - 1], w) ? p : ++p;
    		if (p >= n) break;
    	}
    }
    
    int main()
    {
    	scanf("%s", s + 1), n = strlen(s + 1), build_SA();
    	for(re int i = 1; i <= n; i++) printf("%d ", sa[i]);
    }
    
  • 相关阅读:
    「SOL」开关(LOJ)
    「SOL」星际迷航(LOJ)
    「NOTE」概率生成函数
    「SOL」谢特(LOJ)
    「SOL」重建计划(BZOJ)
    「SOL」Tug of War(洛谷)
    「SOL」同余方程(LOJ)
    「SOL」Bad Cryptography(Codeforces)
    「SOL」小A与两位神仙(洛谷)
    「SOL」Social Distance(AtCoder)
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/15138906.html
Copyright © 2011-2022 走看看