区间树(线段树)基本功能模板

#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;
}
posted @ 2021-07-24 10:59  Selma003  阅读(104)  评论(0)    收藏  举报