关于线段树的初步理解

Posted sun-yiwen-blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于线段树的初步理解相关的知识,希望对你有一定的参考价值。

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;
}

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

以上是关于关于线段树的初步理解的主要内容,如果未能解决你的问题,请参考以下文章

线段树初步

hdu1542线段树(扫描线+离散化)

关于线段树的一些学习笔记——(无限施工中)

关于平衡线段树的一点研究

线段树的思路

可持久化线段树(待补充)