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