[后缀数组]基因突变
描述 Description
最近,jzyz的科学家忽然发现了一种神秘的生物出现在了霞栖湖中,通过提取DNA,科学家发现这个生物的DNA由a.....z共26种碱基对组成,而且这个生物常常容易发生DNA片段的缺失。那么问题来了。科学家想知道DNA片段的缺失对这个生物会产生什么影响。
给你一段长为N的DNA序列(保证全为小写字母),请求出从x到y-1的片段缺失后,忽略前x-1的长度,他们最长还有多长连续序列是相同的?
输入格式 Input Format
第一行为N,表示DNA序列的长度
接下来一行为DNA序列
接下来一行为M,表示M次询问。
接下来的M行为x,y,表示x到y(或y到x)的片段缺失
输出格式 Output Format
对于M次询问,输出M行,每行两个数
样例输入 Sample Input
10
aaaaaabaaa
5
4 7
6 5
6 5
9 8
5 10
样例输出 Sample Output
0
1
1
2
1
/*样例解释
对于第一个询问
从第4个碱基到第6个碱基缺失
故缺失后由
aaaaaabaaa -> aaabaaa
因为rRNA是连续读取的,所以两个DNA的相同的片段是aaa
但是由于我们忽略前三个碱基对,所以相同的长度为0.
对于第二个询问
第五个碱基对缺失
故缺失后由
aaaaaabaaa -> aaaaabaaa
相同片段是5,但是忽略前四个,所以相同为1
*/
注释 Hint
100% 3<=N<=300000 10<=M,x,y<=30000
本质上就是求最长公共前缀。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<ctime> 7 #include<algorithm> 8 #define MAXN 3001000 9 #define INF 0x3f3f3f3f 10 using namespace std; 11 int N,x,y,rank[MAXN],sa[MAXN],p[MAXN],cnt[MAXN],tmp[MAXN],height[MAXN],t[MAXN*4+500]; 12 char s[MAXN]; 13 inline int read() 14 { 15 int x=0,f=1; char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} 18 return x*f; 19 } 20 bool equ(int x,int y,int l) {return rank[x]==rank[y]&&rank[x+l]==rank[y+l];} 21 void doubling() 22 { 23 for(int i=1;i<=N;i++) rank[i]=s[i],sa[i]=i; 24 for(int pos=0,sig=255,l=0,i;pos<N;sig=pos) 25 { 26 for(i=N-l+1,pos=0;i<=N;i++) p[++pos]=i; 27 for(i=1;i<=N;i++) if(sa[i]>l) p[++pos]=sa[i]-l; 28 for(i=1;i<=sig;i++) cnt[i]=0; 29 for(i=1;i<=N;i++) cnt[rank[i]]++; 30 for(i=1;i<=sig;i++) cnt[i]+=cnt[i-1]; 31 for(i=N;i;i--) sa[cnt[rank[p[i]]]--]=p[i]; 32 for(pos=0,i=1;i<=N;i++) 33 tmp[sa[i]]=equ(sa[i],sa[i-1],l)?pos:++pos; 34 for(int i=1;i<=N;i++) rank[i]=tmp[i]; 35 l=!l?1:l<<1; 36 } 37 } 38 void get_height() 39 { 40 for(int i=1,j=0,k;i<=N;i++) 41 { 42 if(!(k=sa[rank[i]-1])) {j=0; continue;} 43 if(j) j--; 44 while(s[i+j]==s[k+j]) j++; 45 height[rank[i]]=j; 46 } 47 } 48 void build(int p,int l,int r) 49 { 50 if(l==r) {t[p]=height[l]; return;} 51 int mid=(l+r)/2; 52 build(p*2,l,mid); 53 build(p*2+1,mid+1,r); 54 t[p]=min(t[p*2],t[p*2+1]); 55 } 56 int getnum(int p,int l,int r) 57 { 58 if(x>r||y<l) return INF; 59 if(x<=l&&y>=r) return t[p]; 60 int mid=(l+r)/2; 61 int lx=getnum(p*2,l,mid),ly=getnum(p*2+1,mid+1,r); 62 return min(lx,ly); 63 } 64 void ask() 65 { 66 int m=read(); 67 for(int i=1;i<=m;i++) 68 { 69 int tx=read(),ty=read(); 70 if(tx==ty) {printf("%d\n",N-tx+1); continue;} 71 if(rank[tx]<rank[ty]) x=rank[tx]+1,y=rank[ty]; 72 else x=rank[ty]+1,y=rank[tx]; 73 printf("%d\n",getnum(1,1,N)); 74 } 75 } 76 int main() 77 { 78 //freopen("cin.in","r",stdin); 79 //freopen("cout.out","w",stdout); 80 N=read(); 81 for(int i=1;i<=N;i++) scanf("%c",&s[i]); 82 doubling(); 83 get_height(); 84 build(1,1,N); 85 ask(); 86 return 0; 87 }