线段树练习题D

                                  Problem D: averyboy的午餐2

                                                  Time Limit: 2 Sec  Memory Limit: 128 MB
 

Description

因为聪明的你帮averyboy解决了荟园阿姨给他的问题,他顺利获得了免费的午餐。这次,averyboy再次来到了荟园,还是那个窗口,还是那位阿姨。。。。。。这次,阿姨不想那么容易让他吃到免费的午餐,所以给出了比上次要难的问题。这不,averyboy又来 求助你了。阿姨这次给出的问题如下.给你一个数组a[1]~a[N],然后给你q次操作,每次操作有三种类型,第一种类型是把数组中的某一个数改为x,第二种操作是询问区间[l, r]之间所有奇数的和,如果这个区间没有奇数,输出0,第三种操作是询问区间[l, r]之间所有偶数的和,如果这个区间没有偶数,输出0.

Input

第一行一个整数T,代表测试数据的组数.
接下来T组测试数据.
每组测试数据第一行两个整数N, q(N, q <= 1e5),分别代表数组a的长度和操作的个数
接下来一行为N个整数,代表数组a
接下来q行,每一行格式为下面三种格式中的一种
1 loc x 将loc位置的数改为x,即a[loc] = x(1 <= loc <= N, 1 <= x <= 1e5)
2 l r 询问区间[l, r]之间奇数的和(1 <= l <= r <= N)
3 l r 询问区间[l, r]之间偶数的和(1 <= l <= r <= N)

 

Output

对于每组测试数据的询问操作,输出结果

解答:这个题目中维护的是奇数和偶数

#include<iostream>
using namespace std;
const long long  Max=100000;
struct Node
{
    int L,R;
    int Single;
    int Double;
}Node[Max<<2];
int a[Max+5];
void pushUp(int i)
{
    int lson = i<<1;
    int rson = lson + 1;
    Node[i].Single = Node[lson].Single + Node[rson].Single;
    Node[i].Double = Node[lson].Double + Node[rson].Double;
}
 
void build(int i, int l, int r)
{
    Node[i].L = l;
    Node[i].R = r;
    Node[i].Single=0;
    Node[i].Double=0;
    if(l == r&&a[l]%2==0)
    {
        Node[i].Double=a[l];
        Node[i].Single=0;
        return;
    }
    if(l == r&&a[l]%2!=0)
    {
        Node[i].Double=0;
        Node[i].Single=a[l];
        return;
    }
    int mid = (l + r)>>1;
    build(i<<1, l, mid);
    build((i<<1)|1, mid + 1, r);
    pushUp(i);
}
void update(int i,int loc,int value)
{
    if(Node[i].L == Node[i].R&&value%2==0)
    {
        Node[i].Double =value;
        Node[i].Single =0;
        return;
    }
      if(Node[i].L == Node[i].R&&value%2!=0)
    {
        Node[i].Double =0;
        Node[i].Single =value;
        return;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(loc <= mid) update(i<<1, loc, value);
    else update((i<<1)|1, loc, value);
    pushUp(i);
}
int querySingle(int i, int l, int r)
{
 
    if(Node[i].L == l && Node[i].R == r)
    {
        return Node[i].Single;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(r <= mid) return querySingle(i<<1, l, r);
    else if(l > mid) return querySingle((i<<1)|1, l, r);
    else
    {
        return querySingle(i<<1, l, mid) + querySingle((i<<1)|1, mid + 1, r);
    }
}
int queryDouble(int i, int l, int r)
{
 
    if(Node[i].L == l && Node[i].R == r)
    {
        return Node[i].Double;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(r <= mid) return queryDouble(i<<1, l, r);
    else if(l > mid) return queryDouble((i<<1)|1, l, r);
    else
    {
        return queryDouble(i<<1, l, mid) + queryDouble((i<<1)|1, mid + 1, r);
    }
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int N,q;
        cin>>N>>q;
        for(int i=1;i<=N;i++)
        {
            cin>>a[i];
        }
        build(1,1,N);
        for(int i=1;i<=q;i++)
        {
            int m,p,q;
            cin>>m>>p>>q;
            if (m==1)
                {
            update(1, p, q);
                }
           if (m==2)
            {
                cout<<querySingle(1,p,q)<<endl;
            }
            if (m==3)
            {
                cout<<queryDouble(1,p,q)<<endl;
            }
        }
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值