线段树(一)

题目来源POJ 3264

要求:在一组给定数值序列中,求给某个区间内的最大值和最小值的差。

   对于初学者来说怎么理解

     build(l, mid, n<<1);
    build(mid + 1, r, n<<1|1)

    s[n].maxx = max(s[n<<1].maxx, s[n<<1|1].maxx);
    s[n].minn = min(s[n<<1].minn, s[n<<1|1].minn); 

在递归构造左右 子孩子之后 s[n].maxx和s[n].minn进行保存的是左右孩子的最值 。

疑惑的地方在于 :这;两个数组怎么保证所求的正好就是同一层两个亲兄弟的最值呢?
   
比如说 n =3 时

build操作:

mid = (1+3)/2 = 2;

接着执行bulid (1,2,2)//此时不是根结点,可以对其进行扩充 ,假如右结点也需要对其进行扩充的话 安排4的结点树就是充裕的

递归调用:

mid = (1+2 )/2= 1;

build(1,1,4)发现左右子树相等;返回

可以对叶子结点用a[1-0]赋值了,赋的值是递归调用这一层的左结点或者右结点,利用这一层的L也就是上一层区间进行划分的一半。

build(2,3,4+1)//这里不确定 到底n是多少。这也直接影响了对递归调用的理解,与下来的顺序相反,对称。

mid = (2+3)/2 = 2;

build (2,2,4) 满足返回条件用a[1]返回。

执行bulid(3,3 ,3) 此时这一次的递归调用函数是在 左子树调用的末尾相对成(我个人理解为本来是从上到下,仍然从下构造到上)

发现 左右子树又相等了 直接用a[3-1]赋值后返回。

 

 

二叉树的结点特点 为

左结点 : 2*k;k为当前深度

右结点: 2*K+1;

 

 

下面是我引用的代码。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000010
int n,a[N];
int ans_x, ans_y;
struct node
{
    int r,l;//定义左右子树; 
    int maxx,minn;//存放左中右 这一组中的最值 
}s[N<<2];//构造的结构体数组元素个数要是结点个数的4倍 线段树数组 随着构建二叉树会不断增加结点数 
void build(int l, int r, int n) //n表示 的含义应该是 结点个数 
{
    s[n].l = l;
    s[n].r = r;
    s[n].maxx = 0;
    s[n].minn = N;
    if(l == r)//叶子结点 
    {
        s[n].maxx = s[n].minn = a[l];//只有一个结点的情况,所以可以如此赋值 
        return;//因为修改了结点的值可以不返回一个具体的值 
    }
    int mid = (l + r) >> 1; //进行拆分 
    build(l, mid, n<<1);//递归构造左子树 
    build(mid + 1, r, n<<1|1);//递归构造右子树 
    s[n].maxx = max(s[n<<1].maxx, s[n<<1|1].maxx); //对构造好的左右字数存储最值 
    s[n].minn = min(s[n<<1].minn, s[n<<1|1].minn);
}
//查找区间的内容  
void query(int l, int r, int n)//l,r表示要查找的区间 
{
    if(s[n].l == l && s[n].r == r)
    {
        ans_x = max(ans_x, s[n].maxx);
        ans_y = min(ans_y, s[n].minn);
        return;
    }
    int mid = (s[n].l + s[n].r) >> 1;
    if(r <= mid)//查找区间在当前区间的左半部分 
        query(l, r, n<<1);
    else if(l > mid) //查找区间在当前位置的右半部分。 
        query(l, r, n<<1|1);
    else//两部分都有的情况 分来两个方向遍历 
    {
        query(l, mid, n<<1);
        query(mid+1, r, n<<1|1);
    }
}
int main()
{
    int m,t,i,x,y;
    while(cin>>m>>t)//输入 某个序列 
    {
        for(i = 1; i <= m; i ++)
            cin >> a[i];
        build(1,m,1);//构造线段树 
        while(t--)
        {
            cin >>x >>y; 
            ans_x = 0;
            ans_y = N;
            query(x,y,1);
           cout << ans_x-ans_y;
        }
    }
    return 0;
}

自己的不足:对递归的思路不够清晰。在算法基础上掌握的不够扎实。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值