zoukankan      html  css  js  c++  java
  • 后缀数组学习笔记

    后缀数组倍增预处理

    #include<iostream>
    #include<cctype>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<ctime>
    #include<cstdlib>
    #include<algorithm>
    #define N 2200000
    #define L 2000000
    #define eps 1e-7
    #define inf 1e9+7
    #define ll long long
    using namespace std;
    inline int read()
    {
        char ch=0;
        int x=0,flag=1;
        while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
        while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*flag;
    }
    char s[N];
    int n,m;
    int c[N],x[N],y[N],sa[N];
    int main()
    {
        scanf("%s",s+1);
        n=strlen(s+1);m=122;
        for(int i=1;i<=n;i++)++c[x[i]=s[i]];
        for(int i=1;i<=m;i++)c[i]+=c[i-1];
        for(int i=n;i>=1;i--)sa[c[x[i]]--]=i;
        for(int k=1;k<=n;k<<=1)
        {
        	//sa[i]当前是按照第一关键字排序的第i名的后缀编号
        	//y[i]是第二关键字的排名为i的数,它第一关键字的位置,根据定义,下面是sa[i]-k 
            int num=0;
            for(int i=n-k+1;i<=n;i++)y[++num]=i;
            for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k; 
            for(int i=1;i<=m;i++)c[i]=0;
    		for(int i=1;i<=n;i++)c[x[i]]++;//按照第一关键字扔到桶里。
    		for(int i=1;i<=m;i++)c[i]+=c[i-1];//求一下前缀。
    		for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
    		//按照第二关键字的顺序倒着取
    		//先看一下这个第二关键字对应的第一关键字的位置
    		//用x来确定一下排名它当前的排名
    		//用桶来算出它在下一次会排在第几名
    		//根据sa数组的定义,在下一轮中,sa[这个排名]=第一关键字的位置 
    		swap(x,y);//只是为了避免多开一个数组,利用y来做一个x的拷贝而已 
    		x[sa[1]]=num=1;
    		for(int i=2;i<=n;i++)
    		x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k])?num:++num; 
    		//这里的y数组是之间的x数组 
    		//分别比较这一个和上一个的两个关键字是否同时相同。 
    		if(num==n)break;
    		m=num; 
        }
        for(int i=1;i<=n;i++)printf("%d ",sa[i]);
        return 0;
    }
    
    

    处理height数组

    height[i]=lcp(sa[i],sa[i-1])
    为了得到height数组,可以先处理出一个h数组
    h[i]=height[rank[i]]
    由此可以推出height[i]=h[sa[i]]
    考虑暴力计算这个h[i]数组是O(n^2)的
    但这里有一个很重要的性质,即h[i]>=h[i-1]-1
    手动模拟一下即可证明。
    因此,这个东西可以O(n)来求。

    void calheight()
    {
    	for(int i=1,k=0;i<=n;i++)
    	{
    		if(k)k--;
    		int j=sa[rank[i]-1];
    		while(s[i+k]==s[j+k])k++;
    		height[rank[i]]=k;
    	}
    }
    

    其中这个k就代表了h[i]的意思

  • 相关阅读:
    1373:鱼塘钓鱼(fishing)
    1261:【例9.5】城市交通路网
    1259:【例9.3】求最长不下降序列
    1260:【例9.4】拦截导弹(Noip1999)
    1258:【例9.2】数字金字塔
    1261:【例9.5】城市交通路网
    1260:【例9.4】拦截导弹(Noip1999)
    1259:【例9.3】求最长不下降序列
    1257:Knight Moves
    [HAOI2008]硬币购物(动态规划、容斥、搜索)
  • 原文地址:https://www.cnblogs.com/Creed-qwq/p/10096145.html
Copyright © 2011-2022 走看看