A Simple Problem with Integers 线段树

郭炜老师的代码  写了下注释 线段树的经典题目

#include<bits/stdc++.h>
using namespace std;

struct CNode
{
    int L,R;
    CNode * pLeft, * pRight;
    long long nSum;//和
    long long Inc;//区间累加量
};
CNode Tree[200010];
int nCount = 0;//充当一个指针作用,管理内存


int Mid( CNode * pRoot)
{
    return (pRoot->L + pRoot->R)/2;//返回区间中间值
}


void BuildTree(CNode * pRoot,int L, int R)//建树
{
    pRoot->L = L;
    pRoot->R = R;
    pRoot->nSum = 0;
    pRoot->Inc = 0;
    if( L == R)//叶节点返回
        return;
    nCount ++;
    pRoot->pLeft = Tree + nCount;
    nCount ++;
    pRoot->pRight = Tree + nCount;
    BuildTree(pRoot->pLeft,L,(L+R)/2);
    BuildTree(pRoot->pRight,(L+R)/2+1,R);
}
void Insert( CNode * pRoot,int i, int v)//插入值 第i个 值为V
{
    if( pRoot->L == i && pRoot->R == i)//如果为叶子节点直接加上累加量结束
    {
        pRoot->nSum = v;
        return ;
    }
    pRoot->nSum += v;//非叶子节点,在该区间加上累加量继续向下一层更新
    if( i <= Mid(pRoot))//小于中间的区间
        Insert(pRoot->pLeft,i,v);
    else//大于中间的区间
        Insert(pRoot->pRight,i,v);
}
void Add( CNode * pRoot, int a, int b, long long c)
{
    if( pRoot->L == a && pRoot->R == b)//区间和目标区间相同,直接加到区间的增加量上就行
    {
        pRoot->Inc += c;
        return ;
    }
    pRoot->nSum += c * ( b - a + 1) ;//如果不相同 把值加到总增加量上后继续向下一层进行
    if( b <= (pRoot->L + pRoot->R)/2)//如果[a,b]完全在中间左边则向左递归
        Add(pRoot->pLeft,a,b,c);
    else if( a >= (pRoot->L + pRoot->R)/2 +1)//同理
        Add(pRoot->pRight,a,b,c);
    else//跨过两边,同理
    {
        Add(pRoot->pLeft,a,(pRoot->L + pRoot->R)/2,c);
        Add(pRoot->pRight,(pRoot->L + pRoot->R)/2 + 1,b,c);
    }
}
long long QuerynSum( CNode * pRoot, int a, int b)
{
    if( pRoot->L == a && pRoot->R == b)
        return pRoot->nSum +(pRoot->R - pRoot->L + 1) * pRoot->Inc ;//如果到达查询的目标区间 直接返回累计值加上区间每一个元素的增加值的和,就是答案
    pRoot->nSum += (pRoot->R - pRoot->L + 1) * pRoot->Inc ;//把区间值加到累计值上往下面带
    Add( pRoot->pLeft,pRoot->L,Mid(pRoot),pRoot->Inc);//
    Add( pRoot->pRight,Mid(pRoot) + 1,pRoot->R,pRoot->Inc);
    pRoot->Inc = 0;//往下带完之后记得归零
    if( b <= Mid(pRoot))      //和上面ADD同理  查绚区间分布不同的三种情况
        return QuerynSum(pRoot->pLeft,a,b);
    else if( a >= Mid(pRoot) + 1)
        return QuerynSum(pRoot->pRight,a,b);
    else
    {
        return QuerynSum(pRoot->pLeft,a,Mid(pRoot)) + QuerynSum(pRoot->pRight,Mid(pRoot) + 1,b);
    }
}
int main()
{
    int n,q,a,b,c;
    string  cmd;
    while(scanf("%d%d",&n,&q)==2){
    nCount = 0;
    BuildTree(Tree,1,n);
    for(int  i = 1; i <= n; i ++ )
    {
        scanf("%d",&a);
        Insert(Tree,i,a);
    }
    for( int i = 0; i < q; i ++ )
    {
       cin>>cmd;
        if ( cmd[0] == 'C' )
        {
            scanf("%d%d%d",&a,&b,&c);
            Add(Tree,a,b,c);
        }
        else
        {
            scanf("%d%d",&a,&b);
            printf("%lld\n",QuerynSum(Tree,a,b));
        }
    }
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值