区间树(线段树)基本功能模板
#include<bits/stdc++.h>
using namespace std;
const int N = 50005, inf = 0x3f3f3f3f; //N是POJ3264的数据范围,
//inf:0x3f3f3f3f的十进制是1061109567,是10^9级别的
int a[N]; //存放值的数组(从1开始)
int sum[N >> 2]; //建了一棵总和数,对应结点的子结点和存放在sum数组中
int maxH[N >> 2]; //同理,最大值树
int minH[N >> 2];
//方法名可以适当缩写的……
//建树方法,从1开始,也可以从0开始,那index分为左右就应该为index * 2 + 1 and index * 2 + 2
void buildSegmentTree(int index, int left, int right){
//index是树中排到哪个位置了,每一行从左往右数记下标
//递归边界(即遇到叶子节点时)
if(left == right){
//直接存储a数组中的值,如果题目要求输入可以在这里写scanf
sum[index] = a[left]; //你要等于a[right]我也没意见
maxH[index] = a[left];
minH[index] = a[left];
}else {
//将建立的区间分成两半
int mid = ((left + right) >> 1);
//求出左孩子结点的值(即从结点left开始,建立范围为a[left]~a[mid])
buildSegmentTree(index * 2, left, mid);
//求出右孩子结点的值(即从结点right开始,建立范围为a[mid]~a[right])
buildSegmentTree(index * 2 + 1, mid + 1, right);
//当前结点的权值为左孩子的值加上右孩子结点的值
sum[index] = sum[index * 2] + sum[index * 2 + 1];
//最大最小值树就是左孩子和右孩子取对应的值
maxH[index] = max(maxH[index * 2], maxH[index * 2 + 1]);
minH[index] = min(minH[index * 2], minH[index * 2 + 1]);
}
}
//将数组x位置的值换成value
void updateSegmentTree(int index, int left, int right, int x, int value){
//找到a[x],修改成value值
//然后改变sum,maxH, minH数组中相应的值
if(left == right){
//在找到该叶子结点时修改
a[x] = value;
sum[index] = value;
maxH[index] = value;
minH[index] = value;
}else {
int mid = (left + right) >> 1;
if (x >= left && x <= mid) { //如果x在左分支
updateSegmentTree(index * 2, left, mid, x, value);
}else { //如果x在右分支
updateSegmentTree(index * 2 + 1, mid + 1, right, x, value);
}
//总和 最大 最小数组都要相应更改
sum[index] = sum[index * 2] + sum[index * 2 + 1];
maxH[index] = max(maxH[index * 2], maxH[index * 2 + 1]);
minH[index] = min(minH[index * 2], minH[index * 2 + 1]);
}
}
//求(L -> R)之间的总和
int querySegmentTree(int index, int left, int right, int L, int R){
//若目标区间与当时区间没有重叠,结束递归返回0
if(left > R || right < L){
return 0;
}else if (L <= left && right <= R){
//若目标区间包含当时区间,直接返回结点值
return sum[index];
}else {
int mid = (left + right) >> 1;
//计算左边区间的值
int sumOfLeft = querySegmentTree(index * 2, left, mid, L, R);
//计算右边区间的值
int sumOfRight = querySegmentTree(index * 2 + 1, mid + 1, right, L, R);
//相加即为答案
return sumOfLeft + sumOfRight;
}
}
//max和min不能像求和一样不在范围内就可以return 0,得像下面这样搞
int calculateMaxOfSegmentTree(int index, int left, int right, int L, int R){
if(L <= left && right <= R){
//若目标区间包含当时区间,直接返回结点值
return maxH[index];
}
int mid = (left + right) >> 1;
int ans = -inf; //求最大值把对比值置最小
if(L <= mid){
//如果有左区间包括在计算范围
ans = max(ans, calculateMaxOfSegmentTree(index * 2, left, mid, L, R));
}
if(mid < R){
//如果有右区间包括在计算范围
ans = max(ans, calculateMaxOfSegmentTree(index * 2 + 1, mid + 1, right, L, R));
}
return ans;
}
int calculateMinOfSegmentTree(int index, int left, int right, int L, int R){
if(L <= left && right <= R){
//若目标区间包含当时区间,直接返回结点值
return minH[index];
}
int mid = (left + right) >> 1;
int ans = inf;
if(L <= mid){
ans = min(ans, calculateMinOfSegmentTree(index * 2, left, mid, L, R));
}
if(mid < R){
ans = min(ans, calculateMinOfSegmentTree(index * 2 + 1, mid + 1, right, L, R));
}
return ans;
}
int main(){
int n;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
//其他的功能自己添加即可,以下是测试数据
/*
for(int i = 0; i <= n << 2; i++){
cout << "a[" << i << "] = " << a[i] << endl;
}
cout << "------------------------" << endl;
*/
buildSegmentTree(1, 1, n);
/*
for(int i = 0; i <= n << 2; i++){
cout << "sum[" << i << "] = " << sum[i] << endl;
}
*/
//把a数组下标为5的值进行更改
updateSegmentTree(1, 1, n, 5, 6);
/*
cout << "------------------------" << endl;
for(int i = 0; i <= 2 * n + 1; i++){
cout << "a[" << i << "] = " << a[i] << endl;
}
cout << "------------------------" << endl;
for(int i = 0; i <= n << 2; i++){
cout << "sum[" << i << "] = " << sum[i] << endl;
}
*/
//求a数组下标3-6的值之和
int ans = querySegmentTree(1, 1, n, 3, 6);
/*
cout << "------------------------" << endl;
cout << "ans = " << ans << endl;
*/
int minn = calculateMinOfSegmentTree(1, 1, n, 4, 6);
/*
cout << "------------------------" << endl;
cout << "minn = " << minn << endl;
*/
int maxx = calculateMaxOfSegmentTree(1, 1, n, 3, 4);
cout << "------------------------" << endl;
cout << "maxx = " << maxx << endl;
return 0;
}
一名计算机科学与技术的女大学生~

浙公网安备 33010602011771号