• 后缀数组乱草


    关于我后缀数组看了两个小时无数篇讲解才自己YY出来这件事,所以写个笔记纪念一下

    假设这是我给自己写的,假设如果有人看那么一定已经知道后缀数组干嘛了

    倍增法求后缀数组

    定义几个数组
    rk[]:表示后缀i的当前排名
    sa[]:表示当前排名为i的后缀的第一个字母的位置
    tob[]:基数排序用的桶
    sec[]:表示按照第二关键字排序后排名为i的后缀的第一个字母的位置

    我们直接对着代码讲?

    	Rep(i,1,n)++tob[rk[i]=s[i]];
    	Rep(i,1,M)tob[i]+=tob[i-1];
    	Dwn(i,n,1)sa[tob[rk[i]]--]=i;
    	for(int w=1;;w<<=1){
    		int p=0;
    		for(int i=n-w+1;i<=n;i++)sec[++p]=i;
    		for(int i=1;i<=n;i++)if(sa[i]>w)sec[++p]=sa[i]-w;
    		for(int i=1;i<=M;i++)tob[i]=0;
    		for(int i=1;i<=n;i++)++tob[rk[i]];
    		for(int i=1;i<=M;i++)tob[i]+=tob[i-1];
    		for(int i=n;i>=1;i--)sa[tob[rk[sec[i]]]--]=sec[i],sec[i]=0;
    		swap(rk,sec);
    		rk[sa[1]]=1,p=1;
    		for(int i=2;i<=n;i++){//sec==fir
    			rk[sa[i]]= ( sec[sa[i]]==sec[sa[i-1]] && sec[sa[i]+w]==sec[sa[i-1]+w]) ? p : ++p;
    		}
    		if(p==n)break;
    		M=p;
    	}
    
    

    首先我们初始化每个后缀i的排名为其ascii码值,并按他们的rk桶排
    对桶数组做前缀和表示每个排名占那些位置
    再初始化sa数组,从后往前考虑每个后缀,后缀i的rank在桶中排第几,那么排第几的后缀就是i,也就是sa数组

    然后考虑把当前两个长度为w的后缀合并起来排序

    我们需要知道每个长为2w的后缀的第一关键字和第二关键字,实际上第一关键字就是后缀i的rk,第二关键字就是后缀i+w的rk

    显然如果长度都不够w了,那么他们是没有第二关键字的,直接把他们排到前面去,也就是,按第二关键字排序时,排名为前1~w的后缀为后w个后缀

    再考虑剩下能做为第二关键字的后缀,我们按照k长的后缀的排名依次考虑排名为1~n的后缀,如果排名为i的后缀开头位置比w大,那么它可以作为第二关键字出现,并且他在其他可能作为第二关键字的后缀中,排名最靠前,那么按第二关键字排序的时候,他作为第二关键字时所对应的后缀(也就是合并成的后缀)的排名就是++p,开头位置为sa[i]-w

    然后我们清空桶准备排序

    先按照所有后缀当前的rk,也就是合并时的第一关键桶排,然后前缀和求出占的位置

    然后我们更新sa数组,其意义是

    我们现在已经按第一关键字在桶中排好序了,我们需要考虑那些第一关键字相同的,再按第二关键字排序一遍

    从n到1枚举,按第二关键字排序时,(排名为i的合并成的后缀的开头位置的第一关键字在桶中的排名)= k ,那么sa[k]就等于排名为i的合并成的后缀的开头位置

    swap没有必要意义,可以当做存一下上一次的rk,然后求合并后的新rk

    首先排第一的rk肯定是1,因为我们是给每个后缀的后边再添一个后缀,就很显然

    然后我们考虑现在排第二到n的后缀

    如果他和上一个一二关键字都相同,那么他们的rk相同,否则加一

    显然每个后缀的长度都不同,最后rk值肯定是1~n

    所有当当前的最大rk到n时,即没用并列的后缀了,我们就排好序了

  • 相关阅读:
    HDU 5438 Ponds
    [HNOI2013]比赛
    [HNOI2009]最小圈
    【模板】高斯消元法
    控制公司 Controlling Companies
    sdut 2878 圆圈
    滑雪
    [ZJOI2010]排列计数
    [HNOI2003]激光炸弹
    [BZOJ 3732]Network
  • 原文地址:https://www.cnblogs.com/Delov/p/15935192.html
Copyright © 2020-2023  润新知