http://fastvj.rainng.com/problem/UVA-12338
题意:给你n个串,然后q次询问,每次询问第l个和第r个相同的子串的长度。
做法:直接全部连起来求一个后缀数组,然后标记每一个串的位置,然后询问的就是rank[pos[l]]到rank[pos[r]]的height数组的最小值。可以用ST表做,建议用ST表,也可以线段树。注意数组开大一点两百万差不多了。
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long ll;
const int N=2000010;
const int inf=0x3f3f3f3f;
int s[N],x[N],y[N],n,m;
int c[N],sa[N],height[N],rk[N];
void Suffix()
{
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);
p=1;x[sa[0]]=0;
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 geth()
{
for(int i=0;i<n;i++) rk[sa[i]]=i;
for(int i=0,k=0;i<n;i++)
{
if(rk[i])
{
if(k) --k;
int j=sa[rk[i]-1];
while(s[i+k]==s[j+k]) k++;
height[rk[i]]=k;
}
}
}
char str[N];
int mp[N],vis[N],len[N];
int tr[N<<2];
void build(int rt,int l,int r)
{
if(l==r)
{
tr[rt]=height[l];
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
tr[rt]=min(tr[rt<<1],tr[rt<<1|1]);
}
int mx=inf;
void query(int rt,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
{
mx=min(mx,tr[rt]);
return;
}
int mid=(l+r)>>1;
if(ql<=mid) query(rt<<1,l,mid,ql,qr);
if(qr>mid) query(rt<<1|1,mid+1,r,ql,qr);
}
int main()
{
int T,k,l,kase=1;scanf("%d",&T);
while(T--)
{
n=0;
int cnt=30,pos=0;
scanf("%d",&k);
for(int i=1;i<=k;i++)
{
scanf("%s",&str);
len[i]=strlen(str);
mp[i]=n;
for(int j=0;j<len[i];j++)
{
s[n++]=str[j]-'a'+1;
}
s[n++]=cnt++;
}
s[n++]=0;
m=cnt;
Suffix();geth();
int q,l,r;
build(1,0,n);
scanf("%d",&q);
printf("Case %d:\n",kase++);
while(q--)
{
scanf("%d%d",&l,&r);
int rk1=rk[mp[l]];
int rk2=rk[mp[r]];
if(rk1>rk2)
swap(rk1,rk2);
if(rk2==rk1)
printf("%d\n",len[l]);
else
{
mx=inf;
query(1,0,n,rk1+1,rk2);
printf("%d\n",mx);
}
}
}
return 0;
}