本文出自:http://blog.csdn.net/svitter
题意:在1~200,000个数中,取一段区间,然后在区间中找出最大的数和最小的数字,求这两个数字的差。
分析:按区间取值,很明显使用的线段树。区间大小取200000 * 4 = 8 * 10 ^5;
进行查询的时候,注意直接判断l, r 与mid的关系即可,一开始写的时候直接与tree[root].L判断,多余了,
逻辑不正确。
#include <iostream> #include <stdio.h> #include <stdlib.h> using namespace std; const int INF = 0xffffff; int maxV, minV; struct Node { int L, R; int Mid(){ return (L+R)/2;} int maxV, minV; //最大数和最小数 //Node *lchild, *rchild; 使用一位数组就可以不使用,可以看做完全二叉树(可能存在空间浪费) }; Node tree[800010]; //四倍叶子节点 void Insert(int root, int n, int val) { //判断叶子节点 if(tree[root].L == tree[root].R) { tree[root].maxV = tree[root].minV = val; return; } //递归更新 tree[root].minV = min(tree[root].minV, val); tree[root].maxV = max(tree[root].maxV, val); //当前为区间节点,寻找叶子节点 if(n < tree[root].Mid()) { Insert(root*2+1, n, val); } else { Insert(root*2+2, n, val); } } void BuildTree(int root, int l, int r) { //建立当前节点 tree[root].L = l; tree[root].R = r; tree[root].maxV = -INF; tree[root].minV = INF; //递归调用建立子树 if(l != r) { BuildTree(root*2+1, l, (l+r)/2); BuildTree(root*2+2, (l+r)/2+1, r); } } void Query(int root, int l, int r) { //递归终止条件 if(l < tree[root].L || r > tree[root].R) return; //判断条件:完全符合区间 if(l == tree[root].L && r == tree[root].R) { maxV = max(maxV, tree[root].maxV); minV = min(minV, tree[root].minV); return; } if(r <= tree[root].Mid()) Query(root*2+1, l, r); else if(l > tree[root].Mid()) Query(root*2+2, l, r); else { Query(root*2+1, l, tree[root].Mid()); Query(root*2+2, tree[root].Mid()+1, r); } } int main() { int N, Q; int val; int a, b; //查找区间[a,b] //while(scanf("%d%d", &N, &Q)) scanf("%d%d", &N, &Q); { BuildTree(0, 1, N); for(int i = 0; i < N; i ++) { scanf("%d", &val); Insert(0, i, val); } //用于测试线段树生成情况 // for(int i = 0; i < 7; i++) // { // printf("No:%d,\nL: %d,\nR: %d,\nMAX: %d,\nMIN: %d,\n\n", i, tree[i].L, tree[i].R, tree[i].maxV, tree[i].minV); // } while(Q--) { maxV = -INF, minV = INF; scanf("%d%d", &a, &b); Query(0, a, b); // printf("max: %d\nmin: %d\n", maxV, minV); printf("%d\n", maxV - minV); } } return 0; }