bzoj3230 相似子串
每个子串都是一个后缀的前缀
每个后缀贡献的子串数目是len-sa[i]-height[i];
因此可以二分找到一个子串的位置,要求某两个子串的最长公共前缀和最长公共后缀,把原串倒过再来一发就好,然后st表O(1)查询;
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<string> 7 #include<cmath> 8 #include<ctime> 9 #include<queue> 10 #include<stack> 11 #include<map> 12 #include<set> 13 #define rre(i,r,l) for(int i=(r);i>=(l);i--) 14 #define re(i,l,r) for(int i=(l);i<=(r);i++) 15 #define Clear(a,b) memset(a,b,sizeof(a)) 16 #define inout(x) printf("%d",(x)) 17 #define douin(x) scanf("%lf",&x) 18 #define strin(x) scanf("%s",(x)) 19 #define LLin(x) scanf("%lld",&x) 20 #define op operator 21 #define CSC main 22 typedef unsigned long long ULL; 23 typedef const int cint; 24 typedef long long LL; 25 using namespace std; 26 void inin(int &ret) 27 { 28 ret=0;int f=0;char ch=getchar(); 29 while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();} 30 while(ch>='0'&&ch<='9')ret*=10,ret+=ch-'0',ch=getchar(); 31 ret=f?-ret:ret; 32 } 33 char s[100010]; 34 int LOG[100010],n,q; 35 cint inf=2147483647; 36 struct string 37 { 38 int sa[100010],h[100010],t[100010],t2[100010],c[100010],rank[100010]; 39 LL sum[100010]; 40 int f[100010][20]; 41 void build_sa(int m) 42 { 43 int *x=t,*y=t2; 44 re(i,0,m-1)c[i]=0; 45 re(i,0,n-1)x[i]=s[i],c[x[i]]++; 46 re(i,1,m-1)c[i]+=c[i-1]; 47 rre(i,n-1,0)sa[--c[x[i]]]=i; 48 for(int k=1;k<=n;k<<=1) 49 { 50 int p=0; 51 rre(i,n-1,n-k)y[p++]=i; 52 re(i,0,n-1)if(sa[i]>=k)y[p++]=sa[i]-k; 53 re(i,0,m-1)c[i]=0; 54 re(i,0,n-1)c[x[y[i]]]++; 55 re(i,1,m-1)c[i]+=c[i-1]; 56 rre(i,n-1,0)sa[--c[x[y[i]]]]=y[i]; 57 swap(x,y); 58 x[sa[0]]=0;p=1; 59 re(i,1,n-1)x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++; 60 if(p>=n)return ; 61 m=p; 62 } 63 } 64 void build_height()// 65 { 66 int k=0; 67 re(i,0,n-1)rank[sa[i]]=i; 68 re(i,0,n-1) 69 { 70 if(k)k--; 71 if(!rank[i])continue ; 72 int j=sa[rank[i]-1]; 73 while(s[i+k]==s[j+k])k++; 74 h[rank[i]]=k; 75 } 76 } 77 void build_sum()// 78 { 79 sum[0]=n-sa[0]; 80 re(i,1,n-1)sum[i]=sum[i-1]+n-h[i]-sa[i]; 81 } 82 void build_RMQ()// 83 { 84 re(i,1,n-1)f[i][0]=h[i]; 85 for(int j=1;(1<<j)<n;j++) 86 for(int i=1;i+(1<<(j-1))<n;i++) 87 f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]); 88 } 89 void init() 90 { 91 build_sa(256); 92 build_height(); 93 build_sum(); 94 build_RMQ(); 95 } 96 void find(LL wei,int &a,int &b)// 97 { 98 int x=lower_bound(sum,sum+n,wei)-sum; 99 a=sa[x],b=sa[x]+h[x]+wei-(x?sum[x-1]:0); 100 } 101 int query(int l,int r)// 102 { 103 l=rank[l],r=rank[r]; 104 if(r<l)swap(l,r);l++; 105 int k=LOG[r-l+1]; 106 return min(f[l][k],f[r-(1<<k)+1][k]); 107 } 108 }A,B; 109 int main() 110 { 111 freopen("in.in","r",stdin); 112 freopen("out.out","w",stdout); 113 inin(n),inin(q); 114 LOG[0]=-1; 115 re(i,1,100000)LOG[i]=LOG[i>>1]+1; 116 strin(s); 117 A.init(); 118 reverse(s,s+n); 119 B.init(); 120 while(q--) 121 { 122 int a1,b1,a2,b2,t; 123 LL l,r,ans=0; 124 LLin(l),LLin(r); 125 if(l>A.sum[n-1]||r>A.sum[n-1]) 126 { 127 cout<<"-1\n"; 128 continue; 129 } 130 A.find(l,a1,b1); 131 A.find(r,a2,b2); 132 t=a1==a2?inf:A.query(a1,a2); 133 t=min(t,min(b1-a1,b2-a2)); 134 ans+=(LL)t*t; 135 t=b1==b2?inf:B.query(n-b1,n-b2); 136 t=min(t,min(b1-a1,b2-a2)); 137 ans+=(LL)t*t; 138 printf("%lld\n",ans); 139 } 140 return 0; 141 }