封装的线段树模板(单点修改,区间查询)

/// 作者:GGN_2015
/// 日期:2020-03-26
/// 主题:封装线段树 

/// 封装一个动态开点指针线段树 
/// 支持单点修改 单点查询 查询区间信息和 

#include <iostream>
#include <queue>

template<typename Type, typename Merge, Type InitValue> /// InitValue 初始值 
class SegmentTree { 
	/// 线段树的下标范围为 int 范围 
	/// Merge 用来实现区间合并 要求结构体 Merge 重载了括号 Type operator()(Type, Type) 
	private:
		struct Node { /// 线段树结点 
			Type data; /// 结点上的数据 
			Node* Lch;
			Node* Rch; /// 左子树右子树 
			Node() { /// 构造函数 
				data = InitValue;
				Lch = Rch = NULL;
			}
		};
		Node *Root; /// 线段树的根节点 
		std::queue<int> WaitQueue; /// 待处理序列 
		const int SegmentTreeIndexMin = -2147483648;
		const int SegmentTreeIndexMax =  2147483647;
		void maintain(Node* node) { /// 更新结点信息 
			if(node != NULL) {
				if(node -> Lch == NULL && node -> Rch == NULL) {
					std::cerr << "SegmentTree::maintain 叶子节点不允许 maintain" << std::endl;
					/// 叶子节点不允许 maintain 
				}else if(node -> Lch == NULL || node -> Rch == NULL) { /// 有一个儿子是空儿子 
					if(node -> Lch == NULL) {
						node -> data = node -> Rch -> data;
					}else {
						node -> data = node -> Lch -> data;
					}
				}else { /// 两个儿子都存在的情况 
					Merge merge; /// 合并函数 
					node -> data = merge(node -> Lch -> data, node -> Rch -> data);
				}
			}
		}
		void UpdatePoint(Node*& rootNow, int L, int R, int pos, Type val) { /// 单点修改 
			/// 在线段树中进行单点修改 
			if(rootNow == NULL) {
				rootNow = new Node; /// 扩充新节点 构造函数会自动被调用 
			}
			if(L == R && L == pos) {
				rootNow -> data = val; /// 成功修改 
				return; 
			}else {
				int mid = ((long long)L + R)/2; /// 注意超大坐标可能会溢出 
				if(L <= pos && pos <= mid) UpdatePoint(rootNow -> Lch, L,   mid, pos, val);
				if(mid < pos && pos <= R)  UpdatePoint(rootNow -> Rch, mid+1, R, pos, val);
				maintain(rootNow); /// 信息合并 
			}
		}
		void Fetch(Node*& rootNow, int L, int R, int pos) { /// 对指定的点进行 Update 
			/// 在线段树中进行单点修改 
			if(rootNow == NULL) {
				rootNow = new Node; /// 扩充新节点 构造函数会自动被调用 
			}
			if(L == R && L == pos) {
				/// 成功定位到当前位置 
				return; 
			}else {
				int mid = ((long long)L + R)/2; /// 注意超大坐标可能会溢出 
				if(L <= pos && pos <= mid) Fetch(rootNow -> Lch, L,   mid, pos);
				if(mid < pos && pos <= R)  Fetch(rootNow -> Rch, mid+1, R, pos);
				maintain(rootNow); /// 信息合并 
			}
		}
		Type& GetPoint(Node*& rootNow, int L, int R, int pos) { /// 找到一个位置的值 
			if(rootNow == NULL) {
				rootNow = new Node; /// 扩充新节点 
			}
			if(L == R && L == pos) {
				return rootNow -> data;
			}else {
				int mid = ((long long)L + R)/2; /// 注意超大坐标可能会溢出 
				if(L <= pos && pos <= mid) {
					Type& tmp = GetPoint(rootNow -> Lch, L,   mid, pos);
					maintain(rootNow); /// 信息合并 
					return tmp;
				}else{
					Type& tmp = GetPoint(rootNow -> Rch, mid+1, R, pos);
					maintain(rootNow); /// 信息合并 
					return tmp;
				}
			}
		}
		void DealWait() { /// 处理等待序列 
			while(!WaitQueue.empty()) {
				int x = WaitQueue.front();
				WaitQueue.pop();
				Fetch(Root, SegmentTreeIndexMin, SegmentTreeIndexMax, x); 
			}
		}
		Type Query(Node*&rootNow, int L, int R, int ql, int qr) { /// 查询区间信息 
			/// 保证有交集 
			if(rootNow == NULL) {
				rootNow = new Node; /// 为空子树建立节点 
			}
			if(ql <= L && R <= qr) {
				return rootNow -> data;
			}
			int mid = ((long long )L + R)/2;
			if(qr <= mid) {
				/// 只需要在左子树中进行查询 
				return Query(rootNow -> Lch, L,   mid, ql, qr);
			}else if(ql >= mid+1) {
				return Query(rootNow -> Rch, mid+1, R, ql, qr);
			}else {
				Type tmpL = Query(rootNow -> Lch, L,   mid, ql, qr);
				Type tmpR = Query(rootNow -> Rch, mid+1, R, ql, qr); 
				Merge merge;
				return merge(tmpL, tmpR); /// 返回合并的信息 
			}
		}
	public:
		SegmentTree() {
			Root = NULL; /// 没有根节点 
		}
		Type& operator[](int index) {
			DealWait(); /// 处理等待操作 
			Type& tmp = GetPoint(Root, SegmentTreeIndexMin, SegmentTreeIndexMax, index);
			WaitQueue.push(index);
			return tmp;
		}
		Type GetMessage(int L, int R) {
			DealWait(); /// 处理等待操作 
			if(L <= R) {
				return Query(Root, SegmentTreeIndexMin, SegmentTreeIndexMax, L, R);
			}else {
				std::cerr << "SegmentTree::GetMessage 查询区间左端点在右端点右侧" << std::endl;
				return InitValue; /// 区间错误 
			}
		}
};

struct Merge { /// 信息合并函数 
	int operator()(int a, int b) { /// 计算区间最大值 
		return a>b ? a: b;
	}
};
SegmentTree<int, Merge, 0> segt;
int main() { /// for debug 
	while(true) {
		int pos, val; std::cin >> pos >> val;
		segt[pos] = val;
		for(int i = 1; i <= 10; i ++) {
			std::cout << "segt[" << i << "] = " << segt[i] << std::endl;
		}
	} 
	return 0;
} 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值