栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

数据结构初级——没有标记的线段树

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

数据结构初级——没有标记的线段树

简介 线段树是啥?能干啥?

维护线段的一个树形结构
可以用来解决一些区间问题
such as 区间修改 区间查询 区间最值啥的
同时也可以支持单点修改,只不过显得有点蠢=。=

为啥要用线段树?

因为朴素的做区间操作复杂度会爆炸,而线段树的复杂度是 O ( l o g n ) O(logn) O(logn)

啥是线段?

就是一个区间了=。=

线段树上的每个点,代表了区间的一段
根节点存储区间[1, n]的信息
每个节点会有两个儿子,将区间从中间断开,分为
[ 1 , ( n + 1 ) 2 ] , [ ( n + 1 ) 2 + 1 , n ] [1, frac{(n + 1)}{2}], [frac{(n + 1)}{2} + 1, n] [1,2(n+1)​],[2(n+1)​+1,n]

直到划分到点 [ 1 , 1 ] , [ 2 , 2 ] . . . [1,1],[2,2]... [1,1],[2,2]...
这样就构成了一个二叉树,所以线段树得入门是肥肠简单的
在实现的时候只需要开4倍空间就可以了,因为所有的节点数量不会超过4n
(不会证)
一般在建树的时候会以1为下标开始建树
这样的话左儿子的下标就可以是k + k,右儿子的下标就是k + k + 1
也就是k >> 1和k >> 1 | 1或者k * 2和k * 2 + 1

上例子

简单的模板题

#include 
using namespace std;
int n, m, a[500001], f[2000001];

void buildtree(int k, int l, int r) {
	if (l == r) {
		f[k] = a[l];
		return;// 到底回溯
	}
	int m = (l + r) >> 1;
	buildtree(k + k, l, m);
	buildtree(k + k + 1, m + 1, r);
	f[k] = f[k + k] + f[k + k + 1];
	
}

inline void add(int k, int l, int r, int x, int y) {
	f[k] += y;
	if (l == r) 
		return;
	int m = (l + r) >> 1;
	if (x <= m) 
		add(k + k, l, m, x, y);
	else 
		add(k + k + 1, m + 1, r, x, y);
}


int calc(int k, int l, int r, int s, int t) {
	if (l == s && r == t)
		return f[k];
	int m = (l + r) >> 1;
	if (t <= m) 
		return calc(k + k, l, m, s, t);
	else
		if (s > m)
			return calc(k + k + 1, m + 1, r, s, t);
		else
			return calc(k + k, l, m, s, m) + calc(k + k + 1, m + 1, r, m + 1, t);
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) 
		cin >> a[i];
	buildtree(1, 1, n);// 以下标为1的点为根节点
	for (int i = 1; i <= m; i++) {
		int t, x, y;
		cin >> t >> x >> y;
		if (t == 1) 
			add(1, 1, n, x, y);
		else 
			cout << calc(1, 1, n, x, y);
	}
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/780086.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号