首页 > 其他分享 >线段树入门(Segment Tree)

线段树入门(Segment Tree)

时间:2024-06-02 15:22:00浏览次数:23  
标签:Node cur nums int tree 线段 Tree vector Segment

线段树入门(Segment Tree)

基本线段树

与树状数组功能类似,实现了点的修改与区间的查询:

首先实现基本的线段树的构建:

#include <iostream>
#include <vector>
using namespace std;

class segmentTree{
public:
    segmentTree(int n, vector<int> nums){
        size = 4 * n;
        tree.resize(size);
        this->nums = nums;
    }
    void build(int l, int r, int i){ // i indexed from 1.
        if (l == r) {
            tree[i] = nums[l];
            return;
        }
        int m = l + (r - l) / 2;
        build(l, m, i * 2);
        build(m+1, r, 2 * i + 1);
        tree[i] = tree[i * 2] + tree[i * 2 + 1];
    }
    vector<int> getTree(){
        return tree;
    }
private:
    int size;
    vector<int> nums; // 
    vector<int> tree;
};

int main(){
    
    int n = 4;
    vector<int> nums{1,2,3,4};
    auto st = segmentTree(n, nums);
    st.build(0, n-1, 1);
    vector<int> tree = st.getTree();
    for (int i=0; i<tree.size(); i++) {
        cout<< tree[i]<<" ";
    }
    return 0;
}

单点修改:

单点修改有两种,增量式修改,即加上某值 (记为 add 方法) nums[i]+=x 或 覆盖式修改,即改为某值 (记为 update 方法)

#include <iostream>
#include <vector>
using namespace std;

class segmentTree{
public:
    segmentTree(int n, vector<int> nums){
        this->n = n;
        size = 4 * n;
        tree.resize(size);
        this->nums = nums;
        build(0, n-1, 1);
    }
    
    void add(int x, int index){ // 对数组中的index加x
        add_p(x, index, 0, n-1, 1);
    }
    void update(int x, int index) {
        update_p(x, index, 0, n-1, 1);
    }
    vector<int> getTree(){
        return tree;
    }
    void printTree(){
        for (int i=0; i<tree.size(); i++) {
            cout<< tree[i]<<" ";
        }
        cout<<endl;
    }
private:
    int n;
    int size;
    vector<int> nums; // 
    vector<int> tree;
    void build(int l, int r, int i){ // i indexed from 1.
        if (l == r) {
            tree[i] = nums[l];
            return;
        }
        int m = l + (r - l) / 2;
        build(l, m, i * 2);
        build(m+1, r, 2 * i + 1);
        tree[i] = tree[i * 2] + tree[i * 2 + 1];
    }
    void add_p(int x, int index, int l, int r, int i) {
        if (l == r) {
            tree[i] += x;
            return;
        }
        int m = l + (r-l) / 2;
        if (index <= m)
            add_p(x, index, l, m, i*2);
        else
            add_p(x, index, m+1, r, i*2+1);
        tree[i] = tree[i * 2] + tree[i * 2 + 1];
    }
    void update_p(int x, int index, int l, int r, int i) {
        if (l == r) {
            tree[i] = x;
            return;
        }
        int m = l + (r-l) / 2;
        if (index <= m)
            add_p(x, index, l, m, i*2);
        else
            add_p(x, index, m+1, r, i*2+1);
        tree[i] = tree[i * 2] + tree[i * 2 + 1];
    }
};

int main(){
    
    int n = 4;
    vector<int> nums{1,2,3,4};
    auto st = segmentTree(n, nums);
    st.printTree();
    st.add(5, 0);
    st.printTree();
    st.update(100, 1);
    st.printTree();
    return 0;
}

离散化方法:

先复制一个数组进行排序,然后通过二分查找的方法定位到元素。注意distance计算的是相隔多少个元素,lower_bound返回的是是大于等于指定元素的迭代器位置。

void discrete(std::vector<int>& nums) {
    int n = nums.size();
    std::vector<int> tmp(nums);
    std::sort(tmp.begin(), tmp.end());
    for (int i = 0; i < n; ++i) {
        nums[i] = std::distance(tmp.begin(), std::lower_bound(tmp.begin(), tmp.end(), nums[i])) + 1;
    }
}

动态线段树Leetcode 699

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

class Solution {
public:
    int N = (int)1e9;
    struct Node{
        Node* ls;
        Node* rs;
        int val;
        int lazy; // 懒标记
        Node(){val=0;lazy=0;ls=nullptr; rs=nullptr;}
    };
    int query_p(int index1, int index2, int l, int r, Node* cur){ // 查询区间上的最高值
        if (index1 <= l && r <= index2) {
            return cur->val;
        }
        pushdown(cur);
        int m = l + (r - l) / 2;
        int left=0, right=0;
        if (index1 <= m) {
            left = query_p(index1, index2, l, m, cur->ls);
        }
        if (index2 > m) {
            right = query_p(index1, index2, m+1, r, cur->rs);
        }
        return max(left, right);
    }
    void update(Node* node, int index1, int index2, int l, int r, int h){
        if (index1 <= l && r <= index2) {
            node->lazy = h;
            node->val = h;
            return;
        }
        pushdown(node);
        int m = l + (r - l) / 2;
        if (index1 <= m) update(node->ls, index1, index2, l, m, h);
        if (index2 > m) update(node->rs, index1, index2, m+1, r, h);
        pushup(node);
    }
    void pushdown(Node* cur){
        if (!cur->ls) cur->ls = new Node();
        if (!cur->rs) cur->rs = new Node();
        if (cur->lazy == 0) {
            return;
        }
        cur->ls->lazy = cur->lazy;
        cur->rs->lazy = cur->lazy;
        cur->ls->val  = cur->lazy;
        cur->rs->val = cur->lazy;
        cur->lazy = 0;
    }
    void pushup(Node* node) {
        node->val = max(node->ls->val, node->rs->val);
    }
    vector<int> fallingSquares(vector<vector<int>>& positions) {
        vector<int> ans;
        Node* root = new Node();
        for (auto pos: positions) {
            int x = pos[0], h=pos[1];
            int cur = query_p(x, x+h-1, 0, N, root);
            update(root, x, x+h-1, 0, N, cur+h);
            ans.push_back(root->val);
        }
        return ans;
    }
};

标签:Node,cur,nums,int,tree,线段,Tree,vector,Segment
From: https://www.cnblogs.com/fireinstone/p/18227160

相关文章

  • CF1961E Turtle and Intersected Segments 题解
    题目链接点击打开链接题目解法不是,我这咋不会做/fn边数很多的最小生成树有一个方法是\(boruvka\),但这个处理完全图的比较方便另一个方法是用到一个\(trick\):连出的图中的环,可以删去最长边扫描线是容易想到的,主要是如何把连的边数缩减到合理的范围内考虑扫描线到当前时刻......
  • 从矩阵角度理解吉司机线段树
    前几天打算学写吉司机线段树,写到区间历史最值的时候炸了,这些标记的复杂性让我有点望而却步,但是当我看到warzone大佬的矩阵角度理解吉司机线段树时,我知道这就是我想看的东西。作为我学完之后的总结,我决定写一篇学习笔记。warzone的题解更为简洁,而我写的这篇会稍微更加详细一点......
  • LeetCode 1305. All Elements in Two Binary Search Trees
    原题链接在这里:https://leetcode.com/problems/all-elements-in-two-binary-search-trees/description/题目:Giventwobinarysearchtrees root1 and root2,return alistcontainingalltheintegersfrombothtreessortedin ascending order.Example1:Input:......
  • 洛谷1803 凌乱的yyy / 线段覆盖 【贪心】
    凌乱的yyy/线段覆盖题目背景快noip了,yyy很紧张!题目描述现在各大oj上有nnn个比赛,每个比赛的开始、结束的时间点是知道的。yyy认为,参加越多的比赛,noip就能......
  • C132 线段树分治 CF1814F Communication Towers
    视频链接: CommunicationTowers-洛谷|计算机科学教育新生态(luogu.com.cn)Problem-1814F-Codeforces//线段树分治O(mlognlogn)#include<iostream>#include<cstring>#include<algorithm>#include<vector>usingnamespacestd;#defineintlong......
  • npm install安装时一直idealTree:npm: sill idealTree buildDeps问题
    解决方案:采用新的镜像地址,进入cmd之后输入:npm命令:npmconfigsetregistryhttps://registry.npmmirror.comyarn命令:yarnconfigsetregistryhttps://registry.npmmirror.com查看配置是完成npmconfiggetregistryyarnconfiggetregistry参考:https:......
  • [数据结构+二叉树+B-Tree和红黑树与B+Tree与hashMap原理+ concurrentHashMap的原理]析
    目录数据结构:你了解过哪些数据结构:这些数据结构的优缺点:二叉树:特点:二叉树适合做磁盘存储吗: 缺点:B-Tree:b-树的查找过程:思考:特点:B+Tree: B+树搜索过程与B树的查询过程没有区别。但实际上有三点不一样:(B+Tree优势)简述B+Tree:不经历IO的情况下,可以直接......
  • CF 947 (Div. 1 + Div. 2) D. Paint the Tree
    时间:24_05_30原题:CodeforcesRound947(Div.1+Div.2)标签:二分/数据结构/[[DFS]]/[[模拟]]/[[树形结构]]题目大意有\(n\)个顶点的树,初始时每个节点都是白色树上有两个棋子,为\(P_A\)和\(P_B\),分别位于\(a\),\(b\)顶点\(P_A\)所在的顶点会被涂成红色,\(P_B\)......
  • C131【模板】线段树分治 P5787 线段树分治
    视频链接: P5787二分图/【模板】线段树分治-洛谷|计算机科学教育新生态(luogu.com.cn)//线段树分治O(mlognlogk)#include<iostream>#include<cstring>#include<algorithm>#include<vector>#include<stack>usingnamespacestd;#definemid((l+r)>&......
  • pyqt Qtreeview分层控件
    pyqtQtreeview分层控件介绍效果代码介绍QTreeView是PyQt中的一个控件,它用于展示分层数据,如目录结构、文件系统等。QTreeView通常与模型(如QStandardItemModel、QFileSystemModel或自定义模型)一起使用,以管理数据和提供视图如何显示数据的规则。效果代码from......