1. 程式人生 > >2018.11.30 bzoj3230: 相似子串(字尾陣列)

2018.11.30 bzoj3230: 相似子串(字尾陣列)

傳送門
字尾陣列入門題。
建立正反兩個字尾陣列算就行了。
程式碼:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,m,q,sa2[N],Log[N],cnt[N];
ll num[N];
char s[N];
struct SA{
	int sa[N],rk[N],ht[N],st[N][21];
	inline void Sort(){
		for(ri i=1;i<=m;++
i)cnt[i]=0; for(ri i=1;i<=n;++i)++cnt[rk[i]]; for(ri i=2;i<=m;++i)cnt[i]+=cnt[i-1]; for(ri i=n;i;--i)sa[cnt[rk[sa2[i]]]--]=sa2[i]; } inline void getsa(){ for(ri i=1;i<=n;++i)rk[i]=s[i]-'a'+1,sa2[i]=i; m=26,Sort(); for(ri w=1,p=0;m^n;w<<=1,p=0){ for(ri i=n-w+1;i<=n;++i)
sa2[++p]=i; for(ri i=1;i<=n;++i)if(sa[i]>w)sa2[++p]=sa[i]-w; Sort(),swap(sa2,rk),rk[sa[1]]=p=1; for(ri i=2;i<=n;++i)rk[sa[i]]=(sa2[sa[i]]==sa2[sa[i-1]]&&sa2[sa[i]+w]==sa2[sa[i-1]+w])?p:++p; m=p; } for(ri i=1,j,k=0;i<=n;ht[rk[i++]]=k)for(k?--k:k,j=sa[rk[i]-1];s[i+k]
==s[j+k];++k); for(ri i=1;i<=n;++i)st[i][0]=ht[i]; for(ri j=1;j<=20;++j)for(ri i=1;i+(1<<j)-1<=n;++i)st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]); } inline int rmq(int l,int r){return min(st[l][Log[r-l+1]],st[r-(1<<Log[r-l+1])+1][Log[r-l+1]]);} inline int query(int l,int r){ l=rk[l],r=rk[r]; if(l>r)l^=r,r^=l,l^=r; return rmq(l+1,r); } }A,B; inline ll read(){ ll ans=0; char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return ans; } inline void solve(int&l,int&r,ll k){ int id=lower_bound(num+1,num+n+1,k)-num; l=A.sa[id],r=A.sa[id]+A.ht[id]+k-num[id-1]-1; } int main(){ freopen("lx.in","r",stdin); n=read(),q=read(),scanf("%s",s+1),Log[0]=-1,A.getsa(),reverse(s+1,s+n+1),B.getsa(); for(ri i=1;i<=n;++i)Log[i]=Log[i>>1]+1,num[i]=num[i-1]+(ll)(n-A.sa[i]+1-A.ht[i]); while(q--){ ll a=read(),b=read(),sum=0,ans; if(a>num[n]||b>num[n]){puts("-1");continue;} int l1,r1,l2,r2; solve(l1,r1,a),solve(l2,r2,b); ans=l1==l2?0x3f3f3f3f:A.query(l1,l2); ans=min(ans,(ll)min(r1-l1+1,r2-l2+1)); sum+=ans*ans; ans=r1==r2?0x3f3f3f3f:B.query(n-r1+1,n-r2+1); ans=min(ans,(ll)min(r1-l1+1,r2-l2+1)); sum+=ans*ans; cout<<sum<<'\n'; } return 0; }