首页 > 其他分享 >线段树

线段树

时间:2023-04-17 11:12:43浏览次数:24  
标签:index right int 线段 tree 节点 left

一. 概述

线段树(Segment Tree)是一种用于处理区间查询和更新的数据结构
常用于解决一维区间相关的问题,如区间最值、区间和、区间乘积等

线段树的基本思想是将区间划分为一些小的子区间,并在每个子区间上维护一些信息
例如该区间的最值、和、乘积等,通过将大区间不断划分为小区间,直到每个小区间只包含一个元素
从而建立一棵二叉树的结构,这棵树就是线段树

二. 构建方式

  1. 将待处理的区间划分为两半,分别对左半部分和右半部分递归地构建线段树。
  2. 对于每个非叶子节点,根据其左子节点和右子节点的信息,更新该节点的信息,例如可以计算最值、和、乘积等。
  3. 当递归到叶子节点时,将叶子节点的信息设置为输入数组中对应位置的元素
构建模板
// 线段树节点结构体
struct TreeNode {
    int left; // 节点区间左边界
    int right; // 节点区间右边界
    int value; // 节点存储的信息,这里以区间最值为例
};
//建树
void build(vector<int>& arr, vector<TreeNode>& tree, int index, int left, int right)
//更新
void update(vector<TreeNode>& tree, int index, int pos, int value)
//查询
int query(vector<TreeNode>& tree, int index, int left, int right)
常用C++做题模板
// 构建线段树的函数,做题arr和tree可用全局变量,不用传入函数
void build(vector<int>& arr, vector<TreeNode>& tree, int index, int left, int right) {
    tree[index].left = left;
    tree[index].right = right;
    // 叶子节点,存储输入数组的元素值
    if (left == right) {
        tree[index].value = arr[left];
        return;
    } 
        // 非叶子节点,递归构建左子树和右子树
        int mid = (left + right) / 2;
        build(arr, tree, index * 2 + 1, left, mid);//递归建左树
        build(arr, tree, index * 2 + 2, mid + 1, right);//递归建右树
        // 更新当前节点的信息,这里以区间最值为例
        tree[index].value = min(tree[index * 2 + 1].value, tree[index * 2 + 2].value);
}

int query(vector<TreeNode>& tree, int index, int left, int right) {
    // 当前节点区间与查询区间完全重合,直接返回节点存储的信息
    if (tree[index].left == left && tree[index].right == right) 
        return tree[index].value;
    else {
        // 否则,根据查询区间与节点区间的关系递归查询左子树或右子树
        int mid = (tree[index].left + tree[index].right) / 2;
        // 查询区间完全位于左子树
        if (right <= mid) 
            return query(tree, index * 2 + 1, left, right);
        // 查询区间完全位于右子树
        else if (left > mid) 
            return query(tree, index * 2 + 2, left, right);
        // 查询区间同时位于左子树和右子树,取两者查询结果的最值
        else 
            return min(query(tree, index * 2 + 1, left, mid), query(tree, index * 2 + 2, mid + 1, right));
    }
}

// 区间更新的函数
void update(vector<TreeNode>& tree, int index, int pos, int value) {
    if (tree[index].left == tree[index].right) {
        // 叶子节点,更新节点存储的信息
        tree[index].value = value;
    } else {
        // 非叶子节点,根据更新位置与节点区间的关系递归更新左子树或右子树
        int mid = (tree[index].left + tree[index].right) / 2;
        if (pos <= mid)// 更新位置位于左子树
        update(tree, index * 2 + 1, pos, value);
         else // 更新位置位于右子树
        update(tree, index * 2 + 2, pos, value);
        // 更新当前节点的信息,这里以区间最值为例
        tree[index].value = min(tree[index * 2 + 1].value, tree[index * 2 + 2].value);
      }
}

三. 实例

1. 子数组中占绝大多数的元素
点击查看代码

标签:index,right,int,线段,tree,节点,left
From: https://www.cnblogs.com/929code/p/17325192.html

相关文章

  • poj2750(线段树+复杂区间合并)
    PottedFlowerPOJ-2750思路:我们将题目简单化,假设我们要求的是序列的最大连续子段和,且可以包括所有数。我们的线段树需要维护这段区间的最大前缀和pre,最大后缀和suf,区间和sum,区间连续最大和mx。那么难点就在于如何由子节点更新父节点。我们可以知道,tr[p].sum=tr[lc].sum......
  • 删除无效的括号(广度优先搜索、字符串)、计算右侧小于当前元素的个数(树状数组、线段
    删除无效的括号(广度优先搜索、字符串)给你一个由若干括号和字母组成的字符串s,删除最小数量的无效括号,使得输入的字符串有效。返回所有可能的结果。答案可以按任意顺序返回。示例1:输入:s="()())()"输出:["(())()","()()()"]示例2:输入:s="(a)())()"输出:["(a())()","(......
  • 【230414-3】有3种不同颜色的灯泡,要在如图所示的6个点A、B、C,A',B‘,C’上各安装1个灯
    ......
  • poj2777(线段树)
    CountColorPOJ-2777思路:暴力能过,线段树维护这个区间的颜色,如果是混色则置为1,如果是单一颜色则设为这个颜色,修改就是正常的区间修改,区间查询就要变一下。还有题解是用二进制做得,可以学一下。#define_CRT_SECURE_NO_WARNINGS1#include<algorithm>#include<fstream>#inc......
  • 线段树(单点修改,区间查询)
    题目描述如题,已知一个数列,你需要进行下面两种操作:将某一个数加上 x求出某区间每一个数的和输入格式第一行包含两个正整数 n,m,分别表示该数列数字的个数和操作的总个数。第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。接下来 ......
  • POJ 2299 Ultra-QuickSort(线段树+离散化)
    题目地址:POJ2299这题曾经用归并排序做过,线段树加上离散化也可以做。一般线段树的话会超时。这题的数字最大到10^10次方,显然太大,但是可以利用下标,下标总共只有50w。可以从数字大的开始向树上加点,然后统计下标比它小即在它左边的数的个数。因为每加一个数的时候,比该数大的数已经加完......
  • POJ 3468 A Simple Problem with Integers(线段树区间更新)
    题目地址:POJ3468打了个篮球回来果然神经有点冲动。。无脑的狂交了8次WA。。居然是更新的时候把r-l写成了l-r。。。这题就是区间更新裸题。区间更新就是加一个lazy标记,延迟标记,只有向下查询的时候才将lazy标记向下更新。其他的均按线段树的来就行。代码如下:#include<iostream>#in......
  • HDU 1166 敌兵布阵(线段树)
    题目地址:HDU1166听说胡浩版的线段树挺有名的。于是就拜访了一下他的博客。详情戳这里。于是就完全仿照着胡浩大牛的风格写的代码。至于原理,鹏鹏学长已经讲的再清晰不过了。我就在下面的代码注释中将原理说明一下吧。来纪念第一发线段树。下面是代码+注释。#include<iostream>#in......
  • ZOJ 3886 Nico Number (线段树)
    题目地址:ZJU3886这个题需要想到一点,因为对一个数x不断取模的话,而且设定他小于模才会进行取余操作的话,那么最多只会进行logx次,因为每次取模都会使x最少折半。然后想到了这点就很好做了。对于区间取模更新操作可以直接暴力更新,维护一个最大值,如果这个区间的最大值小于模的话,就......
  • CAD如何测量连续线段长度?CAD测量连续线段长度步骤
    在CAD绘图过程中,经常会绘制一些连续的线段,如果想要知道这些连续线段长度的话,该怎么操作吗?CAD如何测量连续线段长度?下面小编就以浩辰CAD软件为例来给大家分享一下CAD测量连续线段长度的具体操作步骤吧!CAD测量连续线段长度步骤:浩辰CAD软件中已经考虑到了这种需求,在CAD测量命令(DIST......