线段树

刚刚接触到线段树 , 所谓线段树,就是每个节点存储着数组中某一段的信息(最值或者其他),而叶子节点段长是1,就是数组中的某一个数。

主要操作是建树 , 查询,更新等。


下面是代码,题目参考 HDU 1754 I hate it

注释很详细,可以仔细看,逻辑并不是很复杂、

#include <cstdio>
#include <algorithm>
using namespace std;
//线段树 数组实现
#define MAX_NODE 200001
int in[MAX_NODE];
int segtree[4*MAX_NODE+10];

int build_tree(int root , int left , int right){

  if (left == right){
    segtree[root] = in[left];
   // printf("node = %d value = %d\n" ,root, in[left]);
    return -1;
  }
  if (right<left)
    return -1;
    int mid = (left+right)/2;
  build_tree(root*2 , left , mid);
  build_tree(root*2+1 , mid+1 , right);
  segtree[root] = max(segtree[root*2] , segtree[root*2+1]);
}

int query_tree(int root , int left , int right , int start ,int end){//找出start 到 end 区间的最值

    if(start>right || end<left)//如果该节点记录的区间与查询的区间没有交集
        return -1;
    if (left>=start && right<=end)//如果该节点记录的区间是查询区间的子集
        return segtree[root];

    //剩余情况就是 该节点记录的区间大于待查询的区间 或者 该节点记录的区间与待查询区间有交集
    // 节点记录区间大于待查询区间时,继续递归查询左右子树
    //节点记录的区间与待查询区间有交集 , 左右子树总有一个是记录待查询区间的子集
    int mid = (left+right)>>1;
    int part1 = query_tree(root*2 , left ,mid,start,end);//查询左子树
    int part2 = query_tree(root*2+1 , mid+1 , right ,start , end);//查询右子树

    //下面两个判断是针对节点记录的区间与待查询区间有交集但不是待查询区间的子集。这样肯定左右子树中有一个包含了待查询区间的子集
    if (part1 == -1)//如果左子树不包含待查询区间
        return part2;
    if (part2 == -1)//如果右子树不包含待查询区间
        return part1 ;
        //节点记录区间大于待查询区间时,此时左右子树都包含了待查询区间,所以取左右子树返回的一个最大值最为待求区间的最大值
    return max(part1,part2);//
}
int update_tree(int root , int left , int right , int updatenode , int value){//updatenode是待更新的节点的区间值,value是该节点的值

      if (left == right){
        segtree[root] = value;
        return -1;
      }
      int mid = (left+right)>>1;
      if (mid<updatenode){
        update_tree(root*2+1,mid+1,right,updatenode, value);
      }else{
       update_tree(root*2,left,mid,updatenode,value);
      }
        //回溯更新父节点
        segtree[root]  = max(segtree[root*2],segtree[root*2+1]);
}
int main (){

    int m,n;
    while (~scanf("%d%d",&n,&m)){
                    for (int i = 0 ; i < n ; i ++)
                    scanf("%d",&in[i]);

                    build_tree(1,0,n-1);//root 根节点号码必须从大于0的数开始
                    char c;
                    int a,b;
                    for (int i= 0 ; i < m ; i ++){
                        scanf("\n%c%d%d",&c,&a,&b);
                        if (c=='Q')
                            printf("%d\n",query_tree(0,0,n-1,a,b));
                        else
                            update_tree(0,0,n-1,a-1,b);
                    }


    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值