/// 作者: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;
}
封装的线段树模板(单点修改,区间查询)
最新推荐文章于 2024-07-20 00:02:18 发布