BZOJ 3230 相似子串 ——后缀数组

题目的Source好有趣。

我们求出SA,然后求出每一个后缀中与前面本质不同的字符串的个数。

然后二分求出当前的字符串。

然后就是正反两次后缀数组求LCP的裸题了。

要注意,这时两个串的起点可能会相同,所以需要判掉。

无论读入还是输出都有可能爆long long,要注意

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define maxn 200500
#define inf 0x3f3f3f3f
#define ll long long
 
int _log2[maxn];
 
struct Suffix_Array{
    int s[maxn],cnt[maxn],tmp[maxn],sa[maxn],h[maxn],rk[maxn];
    int st[maxn][21];
    ll pre[maxn],Sum;
    void build(int n,int m)
    {
        n++; int i,j,k;
        F(i,0,2*n+5) sa[i]=tmp[i]=h[i]=rk[i]=0;
        F(i,0,m-1) cnt[i]=0;
        F(i,0,n-1) cnt[rk[i]=s[i]]++;
        F(i,1,m-1) cnt[i]+=cnt[i-1];
        F(i,0,n-1) sa[--cnt[rk[i]]]=i;
        for (k=1;k<=n;k<<=1)
        {
            F(i,0,n-1) {j=sa[i]-k;if(j<0)j+=n;tmp[cnt[rk[j]]++]=j;}
            sa[tmp[cnt[0]=0]]=j=0;
            F(i,1,n-1)
            {
                if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
                sa[tmp[i]]=j;
            }
            memcpy(rk,sa,n*sizeof(int));memcpy(sa,tmp,n*sizeof(int));
            if (j>=n-1) break;
        }
        for (i=k=0;i<n;h[rk[i++]]=k)
            for (k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
        F(i,0,n-1) st[i][0]=h[i];
        F(i,1,20) F(j,0,n-(1<<i)) st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
        F(i,1,n-1) pre[i]=pre[i-1]+n-sa[i]-h[i]-1;
        Sum=pre[n-1];
    }
    int query(int l,int r)
    {
        int t=_log2[r-l+1];
        return min(st[l][t],st[r-(1<<t)+1][t]);
    }
    ll lcp(int a,int b)
    {
        if (a==b) return inf;
        int aa=rk[a],bb=rk[b];
        return query(min(aa,bb)+1,max(aa,bb));
    }
    void find(ll x,int n,int &l,int &r)
    {
        int le=1,ri=n;
        while (le<ri)
        {
            int mid=le+ri>>1;
            if (pre[mid]>=x) ri=mid;
            else le=mid+1;
        }
        int tmp=x-pre[le-1]+h[le];
        l=sa[le];r=l+tmp-1;
    }
}SA,SB;
 
int n,q;
char s[maxn];
 
int main()
{
    F(i,2,maxn-1) _log2[i]=_log2[i>>1]+1;
    scanf("%d%d",&n,&q);
    scanf("%s",s);
    F(i,0,n-1)
    {
        SA.s[i]=s[i]-'a'+1;
        SB.s[n-i-1]=s[i]-'a'+1;
    }
    SA.s[n]=0; SB.s[n]=0;
    SA.build(n,30); SB.build(n,30);
    F(i,1,q)
    {
        ll x,y;
        int xl,xr,yl,yr;
        scanf("%lld%lld",&x,&y);
        if (x>SA.Sum||y>SA.Sum) {printf("-1\n");continue;}
        SA.find(x,n,xl,xr); SA.find(y,n,yl,yr);
        ll lcp=SA.lcp(xl,yl),rcp=SB.lcp(n-yr-1,n-xr-1);
        int l=min(xr-xl+1,yr-yl+1); lcp=min(lcp,(ll)l); rcp=min(rcp,(ll)l);
        printf("%lld\n",lcp*lcp+rcp*rcp);
    }
}

  

posted @ 2017-03-30 16:24  SfailSth  阅读(99)  评论(0编辑  收藏  举报