hrbust/哈理工oj 1867 小伙伴的数据结构【树状数组】

小伙伴的数据结构
Time Limit: 500 MSMemory Limit: 32768 K
Total Submit: 44(20 users)Total Accepted: 13(13 users)Rating: Special Judge: No
Description

给你一些二进制串,我们有对这些数有两种操作。

'I i j'    将[i,j]内的所有数取反(0变1,1变0)

'Q i'    输出第i个数是多少

下标从1开始,输入串允许有前导0


Input

输入包含一个整数T(T<=10000),表示测试样例个数。

每组样例的第一行有一个长度为n的01串(n<=20000)

第二行有一个整数Q(Q<=10000)代表将会有多少个操作


Output

输出每一个Q i的结果

Sample Input

2

0011001100

6

I 1 10

I 2 7

Q 2

Q 1

Q 7

Q 5

1011110111

6

I 1 10

I 2 7

Q 2

Q 1

Q 7

Q 5


Sample Output

Case 1:

0

1

1

0

Case 2:

0

0

0

1


Author
小伙伴们@哈商大

思路:

1、首先看到时间限制500ms,看到Q查询次数比较大,再看题干中的两种操作,区间更新+单点查询,无疑需要使用树状数组或者是线段树之类的来优化查询和更新的操作。


2、对于取反操作,如果能够知道当前这个位子一共改变了多少次,其实也就能知道现在这个位子上的数字是几,如果改变了偶数次,那么这个位子上的数字不变,否则取反。


3、对于统计这个位子一共改变了多少次,归根到底是对于区间更新的操作的一种统计,辣么如何进行区间更新呢?如果您使用的是线段树来解,这里就可以跳过了,直接区间更新+懒惰标记即可。如果您使用的是树状数组来解,这里不难理解:


假设原串是:

01010101;

假设有一种操作,I 1 5表示对【1,5】取反,假设我们有一个数组a【8】,表示每个位子都操作了多少次,暴力情况下,我们使得:a【1】=a【2】=a【3】=a【4】=a【5】=1;对于每个点都进行一次操作,其实我们不妨优化把一堆值更新优化到两个值更新:a【1】=1;a【6】=-1;这样,假设我们询问4号位子上一共改变了多少次的时候,我们可以从a【1】+a【】...+a【4】来查询4号位子上有多少次操作,显然值为1,没有问题。那么我们要询问7号位子上一共改变了多少次的时候,我们照旧a【1】+a【2】+...+a【7】来查询7号位子上有多少次操作,显然值为0,也没有问题。这样我们就可以用树状数组来完成这两个操作了,区间值加和查询+点更新值。


4、处理好字符串,问题就解决了。


AC代码:

#include<stdio.h>
#include<string.h>
using namespace std;
char tmp[20050];
int a[20050];
int tree[1000005];//树
int n;
int lowbit(int x)//lowbit
{
    return x&(-x);
}
int sum(int x)//求和求的是比当前数小的数字之和,至于这里如何实现,很简单:int sum=sum(a[i]);
{
    int sum=0;
    while(x>0)
    {
        sum+=tree[x];
        x-=lowbit(x);
    }
    return sum;
}
void add(int x,int c)//加数据。
{
    while(x<=n)
    {
        tree[x]+=c;
        x+=lowbit(x);
    }
}
int main()
{
    int t;
    int kase=0;
    scanf("%d",&t);
    while(t--)
    {
        memset(tree,0,sizeof(tree));
        scanf("%s",tmp);
        n=strlen(tmp);
        for(int i=1;i<=n;i++)
        {
            a[i]=tmp[i-1]-'0';
        }
        int q;
        scanf("%d",&q);
        printf("Case %d:\n",++kase);
        while(q--)
        {
            char op[5];
            scanf("%s",op);
            if(op[0]=='Q')
            {
                int x;
                scanf("%d",&x);
                int cishu=sum(x);
                //printf("%d\n",cishu);
                if(cishu%2==0)
                {
                    printf("%d\n",a[x]);
                }
                else printf("%d\n",1-a[x]);
            }
            else
            {
                int x,y;
                scanf("%d%d",&x,&y);
                add(x,1);
                add(y+1,-1);
            }
        }
    }
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值