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 }

转载于:https://www.cnblogs.com/swm8023/archive/2012/08/29/2662590.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值