后缀数组求lcp(模版,st模版把

算模版?,不过这东西,顺着思路很好写啊

题目读不懂。。。所以只有rmq和后缀数组是我写的,但是我也是想联系一下后缀数组求lcp,其实没法说吧,顺着st算法的理论写就行


不过为什么log求rmq_st的k,会wa,但是循环判断就不会?????

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<iostream>
#define M(x) memset(x,0,sizeof(x))
using namespace std;
const int N=100005;

int sa[N],c[N],t1[N],t2[N],s[N],height[N],rk[N],f[N][22],n;
char ch[N];

void clear()
{
	M(sa);M(c);M(t1);M(t2);M(height);M(rk);M(f);M(s);
}

void build_sa()  
{  
    int m=29,*x=t1,*y=t2;  
    for (int i=0;i<m;i++) c[i]=0;  
    for (int i=0;i<n;i++) c[x[i]=s[i]]++;  
    for (int i=1;i<m;i++) c[i]+=c[i-1];  
    for (int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;  
      
    for (int k=1;k<=n;k<<=1)  
    {  
        int p=0;  
        for (int i=n-k;i<n;i++) y[p++]=i;  
        for (int i=0;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k;  
          
        for (int i=0;i<m;i++) c[i]=0;  
        for (int i=0;i<n;i++) c[x[y[i]]]++;  
        for (int i=1;i<m;i++) c[i]+=c[i-1];  
        for (int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];  
        swap(x,y);  
        x[sa[0]]=0;p=1;  
        for (int i=1;i<n;i++)  
        x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;  
        if (p>=n) break;  
        m=p;   
    }  
}  
void build_height()  
{  
    int k=0; 
    for (int i=0;i<n;i++) rk[sa[i]]=i;  
    for (int i=0;i<n-1;i++)  
    {  
        if (k) k--;  
        int j=sa[rk[i]-1];  
        while (s[j+k]==s[i+k]) k++;  
        height[rk[i]]=k;  
    }  
}  
void build_st()
{
	for (int i=0;i<n;i++) f[i][0]=height[i];
	for (int k=1;(1<<k)<=n;k++)
	for (int i=0;i<n;i++)
		if (i+(1<<k)-1<n) f[i][k]=min(f[i][k-1],f[i+(1<<(k-1))][k-1]);  
}//预处理,第0名其实是不用算的,因为第0名是哨兵元素啊,我们需用的都是排在1~n-1之间的元素 
int query_RMQ(int u,int v)
{
	int l=rk[u],r=rk[v];
	if (l>r) swap(l,r);
	l++;
	int k=0;
	while((1<<(1+k))<=r-l+1) k++;///为什么我用log过不了???,这里就是只要2^k乘2<=长度,那么就再把k++
	return min(f[l][k],f[r-(1<<k)+1][k]);
}//rmq  
int change(int a)  
{  
    	 if(a<10) return 1;  
    else if(a<100) return 2;  
    else if(a<1000) return 3;  
    else if(a<10000) return 4;  
    else if(a<100000) return 5;  
}  
int main ()  
{  
    while(scanf("%s",ch)!=EOF)  
    {  
        n=strlen(ch);  
        for(int i=0;i<n;++i)  
            s[i]=ch[i]-'a'+1;  
        s[n++]=0;
        build_sa();  
        build_height();  
        build_st();  
  
  
        int q;scanf("%d",&q);  
        long long len1=0,len2=0;  
        for(int kk=1,u,v,lcp,preu=-1,prev=-1;kk<=q;++kk)  
        {  
            scanf("%d%d",&u,&v);  
            if(preu>=0)  
            {  
                if(u==preu)  
                    lcp=n-u;  
                else lcp=query_RMQ(u,preu);  
                lcp=min(lcp,min(v-u,prev-preu));  
                len2+=change(lcp)+v-u-lcp;  
            }  
            else len2+=1+v-u;  
            len1+=v-u+1;  
            len2+=2;  
            preu=u;prev=v;  
        }  
        cout<<len1<<' '<<len2<<endl;  
    }  
    return 0;  
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值