#pragma once
#include <iostream>
#define inf 0x3f3f3f3f
template<typename T>
class SegmentTree {
private:
T* data;
T* tree;
T* add;
int number;
int getLeftIndex(int treeIndex) {
return treeIndex * 2 + 1;
}
int getRightIndex(int treeIndex) {
return treeIndex * 2 + 2;
}
//以treeIndex为根节点,【l,r】创建线段树
void bulidSegmentTree(int treeIndex, int l, int r) {
if (l == r) {
tree[treeIndex] = data[l];
return;
}
// 不使用(l+r)/2因为可能会超出整数范围
int mid = l + (r - l) / 2;
int leftIndex = getLeftIndex(treeIndex);
int RightIndex = getRightIndex(treeIndex);
//分治
bulidSegmentTree(leftIndex, l, mid);
bulidSegmentTree(RightIndex, mid + 1, r);
// tree[treeIndex] = data[l] + data[r];
//融合
tree[treeIndex] = merge(tree[leftIndex],tree[RightIndex]);
}
int query1(int rootNode, int l, int r, int queryL, int queryR) {
if (l == queryL && queryR == r)
return tree[rootNode];
int mid = l + (r - l) / 2;
if (queryR <= mid)
return query1(rootNode * 2 + 1, l, mid, queryL, queryR);
else if (queryL >= mid + 1)
return query1(rootNode * 2 + 2, mid + 1, r, queryL, queryR);
else
return merge(query1(rootNode * 2 + 1, l, mid, queryL, mid),
query1(rootNode * 2 + 2, mid + 1, r, mid+1, queryR));
}
//在【l,r】范围内, 将p的值修改为v
void updataPoint(int rootNode, int l, int r, int p, int v) {
if (l == r) {
tree[rootNode] = v;
return;
}
int mid = l + (r - l) / 2;
if (p <= mid)
updataPoint(rootNode * 2 + 1, l, mid, p, v);
else if( p >= mid+1)
updataPoint(rootNode * 2 + 2, mid + 1, r, p, v);
tree[rootNode] = merge(tree[rootNode*2+1],tree[rootNode*2+2]);
}
void updata(int rootNode, int l, int r, int ql, int qr, int v) {
if (ql <= l && qr >= r) {
add[rootNode] += v;
tree[rootNode] += v * (r - l + 1);
return;
}
pushDwon(rootNode,l,r);
int mid = l + (r - l) / 2;
int left = rootNode * 2 + 1;
int right = rootNode * 2 + 2;
if (ql <= mid)
updata(left, l, mid, ql, qr, v);
if (qr >= mid + 1)
updata(right, mid + 1, r, ql, qr, v);
tree[rootNode] = merge(tree[left],tree[right]);
}
void pushDwon(int rootNode,int l, int r){
if (add[rootNode]) {
int left = rootNode * 2 + 1;
int right = rootNode * 2 + 2;
add[left] += add[rootNode];
add[right] += add[rootNode];
int mid = l + (r - l) / 2;
// tree[left] += v * (mid-l+1); //[l,mid]
// tree[right] += v * (r - mid); //[mid+1,r]
tree[left] = add[rootNode] * (mid - l + 1);
tree[right] = add[rootNode] * (r - mid);
add[rootNode] = 0;
}
}
public:
SegmentTree(){ }
SegmentTree(T arr[],int n){
this->number = n;
data = new T[n];
add = new T[n * 4]{ 0 };
for (int i = 0; i < n; i++) {
data[i] = arr[i];
}
tree = new T[n * 4];
for (int i = 0; i < n * 4; i++) {
tree[i] = inf;
}
bulidSegmentTree(0,0,n-1);
}
T merge(T a, T b) {return a + b;}
int getTreelength() {return 4 * number;}
void println() {
cout << "[ ";
for (int i = 0; i < getTreelength(); i++) {
if (tree[i] != inf)
cout << tree[i];
else
cout << "NUll";
if (i < getTreelength() - 1)
cout << ",";
}
cout << " ]" << endl;
}
//区间查询
int query1(int queryL, int queryR) {
return query1(0, 0, number - 1, queryL, queryR);
}
//点更新 P位置的值更新为v
void updataPoint(int p, int v) {
updataPoint(0, 0, number-1, p, v);
}
//区间更新
void updata(int l, int r, int v) {
updata(0, 0, number - 1, l, r, v);
}
};
#include <iostream>
#include "SegmentTree.h"
using namespace std;
int main()
{
int arr[] = { 1,2,3,4,5,6 };
SegmentTree<int> segment(arr, 6);
segment.println();
cout << segment.query1(0, 5) << endl;
//segment.updataPoint(1,3);
//cout << segment.query1(0, 5) << endl;
cout << segment.query1(0, 2) << endl;
segment.updata(0, 2, 2);
cout << segment.query1(0, 2) << endl;
system("pause");
return 0;
}
SegmentTree 的基本操作
最新推荐文章于 2021-01-27 16:05:41 发布