HDOJ 4046 - Panda 树状数组维护

              题意:

                       给了一列字符串(最长50000)...字符串仅由w,b组成..现在有两个操作..

                      0 l r : 询问区间[l,r]有多少个wbw..输出..

                      1 x c: 将第x位置变成c(c=w or b)

              题解:

                       大致的思想是先用树状数组统计出前缀和..询问的时候就可以直接得出一段的wbw个数了..而修改..则将与修改位相关的前缀和都置为0..然后重新计算...

                       做的时候要注意一些处理..我用树状数组询问一点x是问从1~x有多少个wbw...一般的问题都是sum[r]-sum[l-1]得出区间[l,r]的所需个数...而对于一个区间的询问如 wbw ...询问[2,3](我的本题字符串下标设置为从1开始)...此时sum[1]=0,sum[3]=1..答案为1..显然是错的...因为2的位置让3号位得不到1..又如wbwbw..询问[2,5]..sum[1]=0,sum[5]=2...答案为2..显然也是错的..询问[4,5]..sum[3]=1,sum[5]=2..答案为1..同样也不对....问题就出在计算[l,r]里wbw的个数时.右界可以用sum[r]..而左界要到l的右侧来计算.因为如果计算r的个数时计算了 *l****r  这种..跨过l的不应该算..


Program:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define MAXN 50505
using namespace std;
char s[MAXN],c;
int sum[MAXN],A[MAXN],n;
void update(int k,int x)
{
      while (k<=n)
      {
             sum[k]+=x;
             k+=k&(-k);
      }
}
int query(int k)
{
      int ans=0;
      while (k)
      {
             ans+=sum[k];
             k-=k&(-k);
      }
      return ans;
}
int main()
{ 
      int T,cas,i,m,t,l,r,x; 
      scanf("%d",&T);
      for(int cas=1;cas<=T;++cas)
      {
              scanf("%d%d",&n,&m);
              printf("Case %d:\n",cas);
              if (!n) continue;
              s[0]='!';
              scanf("%s",s+1);
              memset(sum,0,sizeof(sum));
              memset(A,0,sizeof(A));
              for (i=3;i<=n;i++)
                  if (s[i-2]=='w' && s[i-1]=='b' && s[i]=='w') A[i]=1,update(i,1); 
              while (m--)
              {
                    scanf("%d",&t);
                    if (!t) 
                    {
                            scanf("%d%d",&l,&r),l+=3,r++;
                            l=min(l,r+1);
                            printf("%d\n",max(0,query(r)-query(l-1)));
                    }
                    else
                    {
                            scanf("%d %c",&x,&c),x++;
                            if (s[x]==c) continue;
                            s[x]=c;
                            l=max(x,3),r=min(n,x+2);
                            for (i=l;i<=r;i++)
                            {
                                     update(i,-A[i]),A[i]=0; 
                                     if (s[i-2]=='w' && s[i-1]=='b' && s[i]=='w')
                                          A[i]=1,update(i,1);
                            }
                    }
              }
      }
      return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值