【全网最强解析】--线段树--C语言/C++

目录

一.线段树是什么?(线段树的定义)

 二.线段树的作用(线段树适合些什么题型)

三.线段树的理解

线段树的功能介绍

1.线段树的定义

c语言 实现

 c++ 实现

2. 线段树的创建

 c语言 实现

  c++ 实现

3.线段树的懒标记

 c语言 实现

  c++ 实现

 4.线段树的查询

 c语言 实现

  c++ 实现

 5.线段树的更新节点值

c语言 实现

 c++ 实现

 6.线段树的更新区间节点值

c语言 实现

 c++ 实现

代码总和 

四.总结

五.学习视频


一.线段树是什么?(线段树的定义)

线段树(Segment Tree)是一种常见的数据结构,用于处理区间查询和更新问题。它将给定的区间划分为若干个子区间,每个子区间对应着线段树中的一个节点。通过构建线段树,我们可以在对数时间内处理区间查询和更新操作,这极大地提高了问题的解决效率。

 二.线段树的作用(线段树适合些什么题型)

1.最小值最大值总和

2.区间更新的最小值最大值总和等等

三.线段树的理解

线段树通常是一棵平衡二叉树,每个节点都包含一个区间范围以及对应的值。通过预处理的方式,我们可以在构建线段树时,将原始数组中的元素进行合并,从而实现区间查询和更新的高效操作。

线段树的功能介绍

1.线段树的定义

如果我们已经知道有n个节点了,node数组大小一般为数据量的4倍

如果它是一颗完全二叉树,node数组大小可以为数据量的2倍

如果它不是是一颗完全二叉树,node数组大小需要为数据量的4倍(像下图这样)

c语言 实现

//定义线段树的节点信息(值和懒标记)
int max(int a, int b) {
    if (a > b)return a;
    return b;
}
typedef struct node {
    int date, lazy;
};
node[4*n];

 c++ 实现

// 定义线段树的节点信息(值和懒标记)
struct Node {
    int date, lazy;
};

2. 线段树的创建

 c语言 实现

void build(node tree[], int date[], int rt, int left, int right) {
	//只有一个孩子即使他自己的最大值,也是叶子节点
	if (left == right) {
		date[rt] = date[left];
		return;
	}
	int mid = left + (right - left) / 2;
	//递归左子树
	build(tree, date, 2 * rt, left, mid);
	//递归右子树
	build(tree, date, 2 * rt + 1, mid + 1, right);
	tree[rt].date = max(tree[2 * rt].date, tree[2 * rt + 1].date);
}

  c++ 实现

// tree表示线段树,date表示输入的数据,rt表示当前节点,
// left  right表示当前节点的左右边界
void build(vector<Node>& tree, const vector<int>& date, int rt, int left, int right) {
    if (left == right) {
        tree[rt].date = date[left];
        tree[rt].lazy = 0;
        return;
    }
    int mid = left + (right - left) / 2;
    build(tree, date, 2 * rt, left, mid);
    build(tree, date, 2 * rt + 1, mid + 1, right);
    tree[rt].date = max(tree[2 * rt].date, tree[2 * rt + 1].date);
    tree[rt].lazy = 0;
}

3.线段树的懒标记

 c语言 实现

void pushDown(node tree[], int rt) {
	if (tree[rt].lazy != 0) {
		//更新左子树
		tree[rt * 2].date += tree[rt].lazy;
		tree[rt * 2].lazy += tree[rt].lazy;
		//更新右子树
		tree[rt * 2 + 1].date += tree[rt].lazy;
		tree[rt * 2 + 1].lazy += tree[rt].lazy;
		//赋值懒标记为0
		tree[rt].lazy = 0;
	}
}

  c++ 实现

// 懒标记定义
void pushDown(vector<Node>& tree, int rt) {
    if (tree[rt].lazy != 0) {
        tree[rt * 2].date += tree[rt].lazy;
        tree[rt * 2].lazy += tree[rt].lazy;
        tree[rt * 2 + 1].date += tree[rt].lazy;
        tree[rt * 2 + 1].lazy += tree[rt].lazy;
        tree[rt].lazy = 0;
    }
}

 4.线段树的查询

 c语言 实现

//查询节点最大最小值
int query(node tree[], int rt, int left, int right, int ql, int qr) {
	if (ql > right || qr < left) {
		return 0;
	}
	else if (ql <= left && qr >= right) {
		return tree[rt].date;
	}
	pushDown(tree, rt);//处理懒标记
	int mid = left + (right - left) / 2;
	int leftNum = (tree, 2 * rt, left, mid, ql, qr);//左子树
	int rightNum = (tree, 2 * rt + 1, mid + 1, right, ql, qr);//右子树
	return  max(leftNum, rightNum);
}

  c++ 实现

// 查询节点最大值
int query(const vector<Node>& tree, int rt, int left, int right, int ql, int qr) {
    if (ql > right || qr < left) {
        return 0;
    } else if (ql <= left && qr >= right) {
        return tree[rt].date;
    }
    pushDown(tree, rt);
    int mid = left + (right - left) / 2;
    int leftNum = query(tree, 2 * rt, left, mid, ql, qr);
    int rightNum = query(tree, 2 * rt + 1, mid + 1, right, ql, qr);
    return max(leftNum, rightNum);
}

 5.线段树的更新节点值

c语言 实现

//更新节点值
void update(node tree[], int rt, int left, int right, int index, int value) {
	if (left == right) {
		tree[rt].date = value;
		tree[rt].lazy = 0;
		return;
	}
	int mid = left + (right - left) / 2;
	pushDown(tree, rt);//处理懒标记
	if (mid >= index){
		update(tree, rt, left, mid, index, value); 
	}
	else{
		update(tree, rt, mid + 1, right, index, value);
	}
	tree[rt].date = max(tree[rt * 2].date, tree[rt * 2 + 1].date);
}

 c++ 实现

// 更新节点值
void update(vector<Node>& tree, int rt, int left, int right, int index, int value) {
    if (left == right) {
        tree[rt].date = value;
        tree[rt].lazy = 0;
        return;
    }
    int mid = left + (right - left) / 2;
    pushDown(tree, rt);
    if (mid >= index) {
        update(tree, rt, left, mid, index, value);
    } else {
        update(tree, rt, mid + 1, right, index, value);
    }
    tree[rt].date = max(tree[rt * 2].date, tree[rt * 2 + 1].date);
}

 6.线段树的更新区间节点值

c语言 实现

//更新一个区间的节点值
void updateRange(node tree[], int rt, int left, int right, int ul, int ur, int value) {
	if (ul > right || ur < left) {
		return;//区间无交集
	}
	if (ul <= left && ur >= right) {
		tree[rt].date += value;//该节点的最大值加一个value
		tree[rt].lazy += value;//设置懒标记
		return;
	}
	int mid = left + (right - left) / 2;
	pushDown(tree, rt);
	updateRange(tree, 2 * rt, left, mid, ul, ur, value);
	updateRange(tree, 2 * rt + 1, mid, right, ul, ur, value);
	tree[rt].date = max(tree[rt * 2].date, tree[rt * 2 + 1].date);
}

 c++ 实现

// 更新一个区间的节点值
void updateRange(vector<Node>& tree, int rt, int left, int right, int ul, int ur, int value) {
    if (ul > right || ur < left) {
        return;
    }
    if (ul <= left && ur >= right) {
        tree[rt].date += value;
        tree[rt].lazy += value;
        return;
    }
    int mid = left + (right - left) / 2;
    pushDown(tree, rt);
    updateRange(tree, 2 * rt, left, mid, ul, ur, value);
    updateRange(tree, 2 * rt + 1, mid + 1, right, ul, ur, value);
    tree[rt].date = max(tree[rt * 2].date, tree[rt * 2 + 1].date);
}

代码总和 

#define  _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <string.h>
//定义线段树的节点信息(值和懒标记)
int max(int a, int b) {
	if (a > b)return a;
	return b;
}
typedef struct node {
	int date, lazy;
};

//tree表示线段树,date表示输入的数据,rt表示当前节点,
// left  right表示当前节点的左右边界
//这里的左右边界都是数组的索引
void build(node tree[], int date[], int rt, int left, int right) {
	//只有一个孩子即使他自己的最大值,也是叶子节点
	if (left == right) {
		date[rt] = date[left];
		return;
	}
	int mid = left + (right - left) / 2;
	//递归左子树
	build(tree, date, 2 * rt, left, mid);
	//递归右子树
	build(tree, date, 2 * rt + 1, mid + 1, right);
	tree[rt].date = max(tree[2 * rt].date, tree[2 * rt + 1].date);
}
//懒标记定义
void pushDown(node tree[], int rt) {
	if (tree[rt].lazy != 0) {
		//更新左子树
		tree[rt * 2].date += tree[rt].lazy;
		tree[rt * 2].lazy += tree[rt].lazy;
		//更新右子树
		tree[rt * 2 + 1].date += tree[rt].lazy;
		tree[rt * 2 + 1].lazy += tree[rt].lazy;
		//赋值懒标记为0
		tree[rt].lazy = 0;
	}
}
//查询节点最大最小值
int query(node tree[], int rt, int left, int right, int ql, int qr) {
	if (ql > right || qr < left) {
		return 0;
	}
	else if (ql <= left && qr >= right) {
		return tree[rt].date;
	}
	pushDown(tree, rt);//处理懒标记
	int mid = left + (right - left) / 2;
	int leftNum = (tree, 2 * rt, left, mid, ql, qr);//左子树
	int rightNum = (tree, 2 * rt + 1, mid + 1, right, ql, qr);//右子树
	return  max(leftNum, rightNum);
}
//更新节点值
void update(node tree[], int rt, int left, int right, int index, int value) {
	if (left == right) {
		tree[rt].date = value;
		tree[rt].lazy = 0;
		return;
	}
	int mid = left + (right - left) / 2;
	pushDown(tree, rt);//处理懒标记
	if (mid >= index){
		update(tree, rt, left, mid, index, value); 
	}
	else{
		update(tree, rt, mid + 1, right, index, value);
	}
	tree[rt].date = max(tree[rt * 2].date, tree[rt * 2 + 1].date);
}
//更新一个区间的节点值
void updateRange(node tree[], int rt, int left, int right, int ul, int ur, int value) {
	if (ul > right || ur < left) {
		return;//区间无交集
	}
	if (ul <= left && ur >= right) {
		tree[rt].date += value;//该节点的最大值加一个value
		tree[rt].lazy += value;//设置懒标记
		return;
	}
	int mid = left + (right - left) / 2;
	pushDown(tree, rt);
	updateRange(tree, 2 * rt, left, mid, ul, ur, value);
	updateRange(tree, 2 * rt + 1, mid, right, ul, ur, value);
	tree[rt].date = max(tree[rt * 2].date, tree[rt * 2 + 1].date);
}

四.总结

总的来说,线段树是一种高效的数据结构,适用于解决需要频繁进行区间操作的问题。通过合理构建线段树,可以在较短的时间内完成区间查询和更新操作,提高算法的效率。

五.学习视频

线段树_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1vhPoeXEFf/?spm_id_from=333.1387.homepage.video_card.click&vd_source=ddbcf617257651579074a19fa12d5236

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值