HDU 4339 Query [树状数组]

  维护两个字符串,操作一可以将其中一个字符串的一个字符进行修改,操作二是查询从某一位开始的最长公共串。

  这题比较简单,只要维护一个数组,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 }
posted @ 2012-08-29 19:50  Burn_E  阅读(242)  评论(0编辑  收藏  举报