九度 1544 数字序列区间最小值(朴素线段树)

题目

给定一个数字序列,查询任意给定区间内数字的最小值。

 

思路

1. 第一反应, 这是在考察 线段树, 链接里的 blog 讲的很不错, 清晰易懂

2. 这道题不需要考虑插入或者删除线段, 只需要 build 和 统计

3. 建树的话, 先考虑 node 节点的设计, 题目要求的是区间最小值, 所以自然需要一个域保留当前 node 节点表示区间的最小值.

 

class Node {
public:
    int left, right;
    Node *lchild, *rchild;
    int minVal;
};

 

 

4. 然后进行递归建树. 区间 [a,b]的最小值 是由 [a,mid] 和 [mid+1, b] 确定的, 典型的后序遍历模式

Node* buildTree(int a, int b) {
    if(a == b) {
        Node *newNode = new Node();
        newNode->minVal = arr[a-1];
        newNode->left = a;
        newNode->right = b;
        newNode->lchild = NULL;
        newNode->rchild = NULL;
        return newNode;
    }

    int mid = (a+b) >> 1;

    Node* lNode = buildTree(a, mid);
    Node* rNode = buildTree(mid+1, b);

    Node* newNode = new Node();
    newNode->left = a;
    newNode->right = b;
    newNode->lchild = lNode;
    newNode->rchild = rNode;
    newNode->minVal = min(lNode->minVal, rNode->minVal);
    return newNode;
}

 

OK, 树建好了, 现在, 我们拥有这个样子的树了

 

5. 最后进行统计

统计是一个 topDown 的搜索过程, log(n) 时间复杂度

递归的退出条件是 a = left, b = right

int search(Node* root, int a, int b) {
    if(root->left == a && root->right == b) {
        return root->minVal;
    }else{
        int mid = (root->left+root->right)>>1;
        if(b <= mid)
            return search(root->lchild, a,b);
        else if(a > mid)
            return search(root->rchild, a, b);
        else {
            int lmin = search(root->lchild, a, mid);
            int rmin = search(root->rchild, mid+1, b);
            return min(lmin, rmin);
        }
    }
}

 

代码 

#include <iostream>
#include <stdio.h>
using namespace std;

const int INFS = 0X3F3F3F3F;

class Node {
public:
    int left, right;
    Node *lchild, *rchild;
    int minVal;
};

int arr[200000];

Node* buildTree(int a, int b) {
    if(a == b) {
        Node *newNode = new Node();
        newNode->minVal = arr[a-1];
        newNode->left = a;
        newNode->right = b;
        newNode->lchild = NULL;
        newNode->rchild = NULL;
        return newNode;
    }

    int mid = (a+b) >> 1;

    Node* lNode = buildTree(a, mid);
    Node* rNode = buildTree(mid+1, b);

    Node* newNode = new Node();
    newNode->left = a;
    newNode->right = b;
    newNode->lchild = lNode;
    newNode->rchild = rNode;
    newNode->minVal = min(lNode->minVal, rNode->minVal);
    return newNode;
}

int search(Node* root, int a, int b) {
    if(root->left == a && root->right == b) {
        return root->minVal;
    }else{
        int mid = (root->left+root->right)>>1;
        if(b <= mid)
            return search(root->lchild, a,b);
        else if(a > mid)
            return search(root->rchild, a, b);
        else {
            int lmin = search(root->lchild, a, mid);
            int rmin = search(root->rchild, mid+1, b);
            return min(lmin, rmin);
        }
    }
}

int main() {
    freopen("testcase.txt", "r", stdin);
    int len;
    while(scanf("%d", &len) != EOF) {
        for(int i = 0; i < len; i ++)
            scanf("%d", &arr[i]);
        Node *root = buildTree(1, len);
        int queries;
        scanf("%d", &queries);
        for(int i = 0; i < queries; i ++) {
            int a, b;
            scanf("%d%d", &a, &b);
            int res = search(root, a, b);
            printf("%d\n",res);
        }
    }
    return 0;
}

 

 

posted @ 2014-03-01 21:39  SangS  阅读(292)  评论(0编辑  收藏  举报