【题目描述】
给定两个字符串,有两个操作
1--把其中一个串的某个位置的字符变换;
2--询问以某个位置开头的两个串完全相同的最大长度。
【分析】
可以两个字符串的相关信息转化为长为l的一个序列x(l=max(l1,l2)),若在i处两字符相同则x[i]=1否则x[i]=0,
每次更新就是线段树的单点更新,最后的询问就是从i开始的连续的最长的1的长度。
这题的更新很简单,问题是如何处理询问。
我的办法是记录区间内以左端点开始的最长的连续1的长度,询问的时候,如果点n正好被左端点开始的连续1序列覆盖,则递归结束。
否则继续递归左儿子或者右儿子。另外还要处理下横跨区间的问题(具体见代码)。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define N 1000010 5 #define lson l,m,n<<1 6 #define rson m+1,r,n<<1|1 7 using namespace std; 8 char s1[N],s2[N]; 9 int x[N]; 10 int s[N<<2]; 11 void PushUp(int n,int m){ 12 s[n]=s[n<<1]; 13 if(s[n<<1]==(m-(m>>1))) 14 s[n]+=s[n<<1|1]; 15 } 16 void build(int l,int r,int n){ 17 if(l==r){ 18 s[n]=x[l]?1:0; 19 return; 20 } 21 int m=(l+r)>>1; 22 build(lson); 23 build(rson); 24 PushUp(n,r-l+1); 25 } 26 void update(int nn,int l,int r,int n){ 27 if(l==r){ 28 s[n]=x[l]?1:0; 29 return; 30 } 31 int m=(l+r)>>1; 32 if(nn<=m) 33 update(nn,lson); 34 else 35 update(nn,rson); 36 PushUp(n,r-l+1); 37 } 38 int query(int nn,int l,int r,int n){ 39 if(nn-l+1<=s[n]) 40 return l+s[n]-nn; 41 int m=(l+r)>>1; 42 if(nn<=m){ 43 int k=query(nn,lson); 44 if(k==(m-nn+1)) 45 k+=s[n<<1|1]; 46 return k; 47 } 48 else 49 return query(nn,rson); 50 } 51 int main(){ 52 int d=1; 53 int t; 54 scanf("%d",&t); 55 while(t--){ 56 scanf("%s%s",s1,s2); 57 int l1=strlen(s1),l2=strlen(s2); 58 int l=max(l1,l2); 59 for(int i=l1;i<l;i++) 60 s1[i]='#'; 61 for(int i=l2;i<l;i++) 62 s2[i]='#'; 63 for(int i=1;i<=l;i++) 64 x[i]=(s1[i-1]==s2[i-1])?1:0; 65 int q,a,b,c; 66 build(1,l,1); 67 printf("Case %d:\n",d++); 68 scanf("%d",&q); 69 while(q--){ 70 scanf("%d",&a); 71 if(a==2){ 72 scanf("%d",&b); 73 if(x[b+1]==0) 74 puts("0"); 75 else 76 printf("%d\n",query(b+1,1,l,1)); 77 } 78 else{ 79 char xx[5]; 80 scanf("%d%d%s",&b,&c,xx); 81 if(b==1)s1[c]=xx[0]; 82 else s2[c]=xx[0]; 83 x[c+1]=(s1[c]==s2[c])?1:0; 84 update(c+1,1,l,1); 85 } 86 } 87 } 88 return 0; 89 }
浙公网安备 33010602011771号