线段树

//poj1166 求区间连续和
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std ;

const int maxn = 1e6;

/* 
线段树通过将线段离散化构建了一颗二叉查找树的树结构,类似于完全二叉树使用数组实现
离线算法,在logn内完成对区间点的四则运算等值更新,以及区间最值连续和等区间问题和区间某点问题的操作
线段树叶节点是 [a,a]的点区间,中间节点可以存放中间结果,他是完成了对子节点的操作,可以直接使用中间节点的值,这就是在比较的时候使用 
if (ll <= l && rr >= r) return sum[rt] 的原因,从而避免了访问rt叶节点,增加复杂度 
*/  

//线段树的节点定义,左右边界和区间结果数值,这种定义可以多添加几个区间结果数值,比如区间连续和和区间最值 
struct seg{
    int l , r , val ;
}T[maxn];
//预先构建线段树
// m >> 1 | 1 等于 m / 2 + 1 
void build( int l , int r , int pos){
    if( l == r){
        T[pos].l = l ;
        T[pos].r = r ;
        T[pos].val = 0 ;
        return ;
    }

    int mid = (l + r ) >> 1  ;
    T[pos].l = l ;
    T[pos].r = r ;
    T[pos].val = 0 ;
    //左子区间 
    build(l , mid , pos << 1) ;
    //右子区间 
    build(mid + 1 , r , pos << 1 | 1) ;
} 
void ins( int n , int d , int k ){
    //d子区间,不是第d个,而是区间边界是d 
    if( T[k].l == T[k].r && T[k].l == d ){
        T[k].val += n ;
        return ;
    }
    int mid = ( T[k].l  + T[k].r ) >> 1 ;
    if( d <= mid) ins( n , d , k<< 1) ;
    else 
        ins( n , d , k<<1 | 1) ;
    //父节点的区间值来源于两个子区间的区间值 
    T[k].val = T[ k << 1].val + T[ k << 1 | 1].val ; 
}

int query( int l , int r , int k ){
    //线段树使用的左闭右闭的区间 
    //当区间[l,r]包含k区间[T[k].l , T[k].r ] 的时候, 区间[l,r] 的区间值可以来源于k区间 
    if( l <= T[k].l && r>= T[k].r )
        return T[k].val ;

    int ans = 0 ;
    int mid = ( T[k].l + T[k].r ) >> 1  ;
    //k区间的左子区间为[T[k].l , mid ] , 右子区间为[mid + 1 , T[k].r ] 
    //当l<=mid 则证明[l,r] 区间在左子区间有来源 ,去左子区间区间值 
    if( l <=mid )
        ans += query( l , r , k << 1) ;
    //因为右子区间范围[mid + l, T{k],r ] ,则证明区间[l,r] 在右子区间有来源,取右子区间区间值 
    if( r > mid ) 
        ans += query( l , r , k << 1 | 1) ;
    //父区间[l,r] 的区间值为ans  
    return ans ;
}


int main(){
    int a;
    scanf("%d",&a) ;
    for(int i = 1 ;i<= a ;i++){
        int b ;
        scanf("%d"  , & b) ;
        //父区间下标序号为1 , 区间边界[1 , b]  
        build( 1 , b , 1) ;
        for(int j = 1 ; j <= b ; j++){
            int temp ;
            scanf("%d", & temp) ;
            ins( temp , j , 1) ; 
        } 
        printf("Case %d:\n" , i) ;

        char s[11] ;
        while(scanf("%s" , s) && s[0]!='E' ) {
            int c , d;
            scanf("%d%d" , & c , & d) ;
            if( s[0] == 'A') ins( d , c , 1) ;
            else if( s[0] == 'S')
                ins( -d , c , 1) ;
            else{
                int ans = query ( c, d , 1) ;
                printf("%d\n" , ans) ;
            }
        } 
    }
    return 0 ;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值