HDOJ 1166 点更新段查询求和 初级线段树

在Alibaba上碰到了中级的线段树问题,另外在队内集训的时候做2010年的多校联合的题时,遇到了两道线段树。

但是无奈的我只会树状数组。如果用树状数组来段更新,简直是以卵击石嘛~ 

接连受打击,无奈之下只好拜读了下Roba,NOS的博客,他们的教学博客写得很好。

简直是膜拜了~~~

鄙人无奈的弱菜啊~~

线段树基于二叉查询数,通过手动judge可以知道其美妙的结构~

网络上很多的树形图都是错的。

                      (1,6)                                             1

                     /         \                                        /          \

             (1,3)          (4,6)                              2                 3

             /     \            /      \                        /       \           /        \

        (1,2)  (3,3) ( 4,5)  (6,6)             4           5       6          7

        /     \              /      \                    /      \               /     \

   (1,1)  (2,2)   (4,4)  (5,5)           8        9          12     13

上面左图数线段树,右图是每个节点在一维数组中对应的标号。

学过数据结构的同学应该知道二叉树的原理

同样在线段树中也能这样。

每个根节点的左子树标号=当前根节点标号<<1;

每个根节点的右子树标号=当前根节点标号<<1|1;

对于构建二叉树用递归就行了。
稍微理解一下二叉树,对于线段树就很好写了。

当然我写得是最最简单最最基础的线段树,一句话 弱爆了!



#include<stdio.h>
#include<string.h>
#define MAXN 2000001

int sum[MAXN];
void PushUp( int root ){
     sum[root]=sum[root<<1]+sum[root<<1|1];
}


void build( int l,int r,int root )
{
     if( l==r )
     {
         scanf( "%d",&sum[root] );
         return ;
     }
     int m=(l+r)/2;
     build( l,m,root<<1 );
     build( m+1,r,root<<1|1 );
     PushUp(root);
}

void update( int at,int value,int L,int R,int root )
{
     if( L==R ){
         sum[root]+=value;return ;
     }
     int m=(L+R)/2;
     if( at<=m )update(at,value,L,m,root<<1 );
     else update( at,value,m+1,R,root<<1|1 );
     PushUp( root );
}

int query( int l,int r,int L,int R,int root )
{
    int res=0;
    if( l<=L && R<=r )
        return sum[root];
    int m=(L+R)/2;
    if( l<=m )
        res+=query( l,r,L,m,root<<1 );
    if( m<r )
        res+=query( l,r,m+1,R,root<<1|1 );
    return res;
}

int main()
{
    int loop,a,b,c;
    char com[100];
    int index=1;
    scanf( "%d",&loop );
    while( loop-- )
    {
           int i,j,n;
           scanf( "%d",&n );
           build(1,n,1);
           printf( "Case %d:\n",index++ );
           while( scanf( "%s",com ) )
           {
                  if( com[0]=='E' )
                      break;
                  scanf( "%d%d",&a,&b );
                  if( com[0]=='Q' )
                      printf( "%d\n",query(a,b,1,n,1) );
                  else if( com[0]=='A' )
                      update( a,b,1,n,1 );
                  else
                      update( a,-b,1,n,1 );
           }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值