维护两个字符串,操作一可以将其中一个字符串的一个字符进行修改,操作二是查询从某一位开始的最长公共串。
这题比较简单,只要维护一个数组,0表示两个字符串该位字符相同,1表示两个字符串该位字符不同。用树状数组维护前缀和,用sum(i)表示前i个元素的和,如果要查询从第i位开始的最长公共串,只要求满足sum(x)-sum(i)==0的最大x即可,二分去找这个x就行了。复杂度比线段树去做多一个二分的log(N),但是线段树常数比树状数组大不少,所以实际效率是差不多的,而且代码要好写很多。
1 #include <stdio.h> 2 #include <string.h> 3 #define MAXL 1000005 4 int cas,q,op,len,l1,l2,l3; 5 char s[2][MAXL],s3[2]; 6 int c[MAXL]; 7 int lowbit(int x){return x&-x;} 8 void update(int x,int p){ 9 while(x<l1)c[x]+=p,x+=lowbit(x); 10 } 11 int sum(int x){ 12 int ret=0; 13 while(x)ret+=c[x],x-=lowbit(x); 14 return ret; 15 } 16 int main(){ 17 // freopen("test.in","r",stdin); 18 scanf("%d",&cas); 19 for(int ca=1;ca<=cas;ca++){ 20 printf("Case %d:\n",ca); 21 scanf("%s%s",s[0],s[1]); 22 l1=strlen(s[0]),l2=strlen(s[1]); 23 if(l1>l2)l1=l2;l1++; 24 memset(c,0,l1*4); 25 for(int i=1;i<l1;i++) 26 if(s[0][i-1]!=s[1][i-1])update(i,1); 27 scanf("%d",&q); 28 29 while(q--){ 30 scanf("%d",&op); 31 if(op==2){ 32 scanf("%d",&l2);l2++; 33 if(l2>l1){printf("0\n");continue;} 34 int presum=sum(l2-1); 35 int low=l2-1,high=l1,mid; 36 for(;;){ 37 mid=(low+high)/2; 38 if(mid==low)break; 39 if(sum(mid)-presum==0)low=mid; 40 else high=mid; 41 } 42 printf("%d\n",mid-l2+1); 43 }else{ 44 scanf("%d%d%s",&l2,&l3,s3);l2--; 45 if(s[l2][l3]==s3[0])continue; 46 if(s[l2^1][l3]==s3[0])update(l3+1,-1); 47 if(s[l2^1][l3]==s[l2][l3])update(l3+1,1); 48 s[l2][l3]=s3[0]; 49 } 50 } 51 } 52 return 0; 53 }