关于线段树的初步理解

POJ 3264

根据题目意思就是给定一段序列,然后给出几个区间,要求出该段区间中最大值与最小值之差。

首先我想到的是用数组存储这一段序列,然后每次根据区间的左右边界来遍历这个段序列然后找到最大值和最小值,显然这样的方法是最容易想到的,但是可想而知这样的方法会耗费很多的时间,时间复杂度太大。

然后,我进行了第二种思考,就是利用二维数组来存储左边界到右边界的最大值;

(1)如果l==r,那么显然当前区间的最大值和最小值就是l这个位置的数本身

(2)max1[i][j]=max{max[i][j-1],height[j]};

#include <iostream>
#include <algorithm>
using namespace std;
int main(){
    int n,q;
    while(cin>>n>>q){
        int *height=new int[n];
        for(int i=0;i<n;i++){
            cin>>height[i];
        }
        int seta,setb;
        int max1[n][n];
        int min1[n][n];
        for(int i=0;i<n;i++){
            max1[i][i]=height[i];
            min1[i][i]=height[i];
        }
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                max1[i][j]=max(max1[i][j-1],height[j]);
                min1[i][j]=min(min1[i][j-1],height[j]);
            }
        }
        while(q--){
            cin>>seta>>setb;
            cout<<max1[seta-1][setb-1]-min1[seta-1][setb-1]<<endl;
        }
    }
}

但是完成了这样的初步思考之后,由于原问题中的数据范围给的是50000,显然会超过给定的内存范围。

于是,就发现了有线段树这个结构:

#include <iostream>
#include <algorithm>
#define maxn 50000
using namespace std;
int MAX[maxn<<2];
int MIN[maxn<<2];
int A[maxn];
void maximum(int rt){
    MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]);
}
void minmum(int rt){
    MIN[rt]=min(MIN[rt<<1],MIN[rt<<1|1]);
}
void Build(int l,int r,int rt){
    if(l==r){
        MAX[rt]=A[l];
        MIN[rt]=A[l];
        return ;
    }
    
    int m=(l+r)>>1;
    Build(l,m,rt<<1);
    Build(m+1,r,rt<<1|1);
    maximum(rt);
    minmum(rt);
}
int Query(int L,int R,int l,int r,int rt,int &x,int &y){
    if(L<=l&&R>=r){
        x=max(MAX[rt],x);
        y=min(MIN[rt],y);
        return x-y;
    }
    int m=(l+r)>>1;
    if(L<=m) {
        return Query(L,R,l,m,rt<<1,x,y);
    }
    else if(R>m){
        return Query(L,R,m+1,r,rt<<1|1,x,y);
    }
    
}
int main(){
    int n,m,L,R,x,y;
    while(cin>>n>>m){
        for(int i=0;i<n;i++){
            cin>>A[i];
        }
        Build(1,n,1);
        while(m--){
            x=-1,y=300000;
            cin>>L>>R;
        cout<<Query(L,R,1,n,1,x,y)<<endl;
        }
    }
    
    return 0;
}

 就对于上述代码而言是根据查找某段区间的和来修改的,但是还需要对查找部分函数进行更深一步的了解。

原文地址:https://www.cnblogs.com/Sun-Yiwen-blog/p/9863858.html