ACM集训--HDU 1166

线段树模板题:

     hdu1166,先摆模板:


    

(1):线段树的构造 void build(int l, int r, int rt);

主要思想是递归构造,如果当前节点记录的区间只有一个值,则直接赋值,否则递归构造左右子树,最后回溯的时候给当前节点赋值

<span style="font-family:Comic Sans MS;">void Build(int l, int r, int rt)  
{  
    if(l == r)  
    {  
        scanf("%d", &sum[rt]);  
        return ;  
    }  
    int m = ( l + r )>>1;  
  
    Build(lson);  
    Build(rson);  
    PushPlus(rt);  
}</span>


(2):区间查询int query(int node, int begin, int end, int left, int right);

(其中node为当前查询节点,begin,end为当前节点存储的区间,left,right为此次query所要查询的区间)

主要思想是把所要查询的区间[a,b]划分为线段树上的节点,然后将这些节点代表的区间合并起来得到所需信息

<span style="font-family:Comic Sans MS;">int query(int node, int begin, int end, int left, int right)    
{   
    int p1, p2;    
    
    /*  查询区间和要求的区间没有交集  */  
    if (left > end || right < begin)    
        return -1;    
    
    /*  if the current interval is included in  */    
    /*  the query interval return segTree[node]  */  
    if (begin >= left && end <= right)    
        return segTree[node];    
    
    /*  compute the minimum position in the  */  
    /*  left and right part of the interval  */   
    p1 = query(2 * node, begin, (begin + end) / 2, left, right);   
    p2 = query(2 * node + 1, (begin + end) / 2 + 1, end, left, right);    
    
    /*  return the expect value  */   
    if (p1 == -1)    
        return p2;    
    if (p2 == -1)    
        return p1;    
    if (p1 <= p2)    
        return  p1;    
    return  p2;      
}   </span><span style="font-family:FangSong_GB2312;">
</span>

a:单节点更新

<span style="font-family:Comic Sans MS;">void Updata(int node, int begin, int end, int ind, int add)/*单节点更新*/    
{    
    
    if( begin == end )    
    {    
        segTree[node] += add;    
        return ;    
    }    
    int m = ( left + right ) >> 1;    
    if(ind <= m)    
        Updata(node * 2,left, m, ind, add);    
    else    
        Updata(node * 2 + 1, m + 1, right, ind, add);    
    /*回溯更新父节点*/    
    segTree[node] = min(segTree[node * 2], segTree[node * 2 + 1]);     
         
}  </span><span style="font-family: FangSong_GB2312; "> </span>
HDU1166用的就是单节点更新

<span style="font-family:Comic Sans MS;">#include<cstring>   
#include<iostream>   
  
#define M 50005   
#define lson l,m,rt<<1   
#define rson m+1,r,rt<<1|1   
/*left,right,root,middle*/  
  
int sum[M<<2];  
  
inline void PushPlus(int rt)  
{  
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];  
}  
  
void Build(int l, int r, int rt)  
{  
    if(l == r)  
    {  
        scanf("%d", &sum[rt]);  
        return ;  
    }  
    int m = ( l + r )>>1;  
  
    Build(lson);  
    Build(rson);  
    PushPlus(rt);  
}  
  
void Updata(int p, int add, int l, int r, int rt)  
{  
  
    if( l == r )  
    {  
        sum[rt] += add;  
        return ;  
    }  
    int m = ( l + r ) >> 1;  
    if(p <= m)  
        Updata(p, add, lson);  
    else  
        Updata(p, add, rson);  
  
    PushPlus(rt);  
}  
  
int Query(int L,int R,int l,int r,int rt)  
{  
    if( L <= l && r <= R )  
    {  
        return sum[rt];  
    }  
    int m = ( l + r ) >> 1;  
    int ans=0;  
    if(L<=m )  
        ans+=Query(L,R,lson);  
    if(R>m)  
        ans+=Query(L,R,rson);  
  
    return ans;  
}  
int main()  
{     
    int T, n, a, b;  
    scanf("%d",&T);  
    for( int i = 1; i <= T; ++i )  
    {  
        printf("Case %d:\n",i);  
        scanf("%d",&n);  
        Build(1,n,1);  
  
        char op[10];  
  
        while( scanf("%s",op) &&op[0]!='E' )  
        {  
  
            scanf("%d %d", &a, &b);  
            if(op[0] == 'Q')  
                printf("%d\n",Query(a,b,1,n,1));  
            else if(op[0] == 'S')  
                Updata(a,-b,1,n,1);  
            else  
                Updata(a,b,1,n,1);  
  
        }  
    }  
    return 0;  
}  </span>

要学会使用模板,必须好好的理解算法,至少要明确每个变量的意义,思路清晰了,代码也就不是问题
  参考http://blog.csdn.net/metalseed/article/details/8039326



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值