题意:给n个值, Q次询问, 每次询问给定一个区间, 要求输出该区间最大最小值之差
思路:暴力的话每次询问都要遍历多次for循环一定会超时, 用线段树记录区间的信息(左边界右边界, 该区间最大值最小值)
代码:
1 #include<stdio.h> 2 #include<algorithm> 3 #define inf 0x3f3f3f3f 4 using namespace std; 5 6 int n, m, arr[50010]; 7 int ansmax, ansmin; 8 9 struct Tree 10 { 11 int maxx, minn, left, right; //记录区间信息 12 }tree[50010 * 4]; //开四倍空间 13 14 void build(int left, int right, int k) 15 { 16 tree[k].left = left, tree[k].right = right; //区间左右 17 if(tree[k].left == tree[k].right) 18 { 19 tree[k].maxx = tree[k].minn = arr[left]; //分到最后只剩下一个值 记为最大最小值 20 return ; 21 } 22 int mid = (left + right)/2; 23 build(left, mid, k * 2); //往左右儿子构造线段树 24 build(mid + 1, right, k * 2 + 1); 25 tree[k].maxx = max(tree[k * 2].maxx, tree[k * 2 + 1].maxx); //满足区间相加.子区间之间的最大最小值也是父亲区间的最大最小值 26 tree[k].minn = min(tree[k * 2].minn, tree[k * 2 + 1].minn); 27 } 28 29 void query(int k, int left, int right, int find_left, int find_right) 30 { //如果ansmax已经大于等于该点区间最大值,ansmin已经小于等于该点区间最小值 , 不用更新,return 31 if(ansmax >= tree[k].maxx && ansmin <= tree[k].minn) 32 return ; 33 if(find_left == left && find_right == right) 34 { //查询区间刚好是某个节点的区间, 该区间已经记录了最大最小值信息,可以直接调用并return 35 ansmax = max(ansmax, tree[k].maxx); 36 ansmin = min(ansmin, tree[k].minn); 37 return ; 38 } 39 int mid = (left + right)/2; 40 if(find_right <= mid) //查询区间全位于该节点的左儿子区间 41 query(2 * k, left, mid, find_left, find_right); 42 else if(find_left > mid)//查询区间全位于该节点的右儿子区间 43 query(2 * k + 1, mid + 1, right, find_left, find_right); 44 else 45 { //有位于左儿子和右儿子部分 46 query(2 * k, left, mid, find_left, mid); 47 query(2 * k + 1, mid + 1, right, mid + 1, find_right); 48 } 49 } 50 51 int main() 52 { 53 int a, b; 54 scanf("%d%d", &n, &m); 55 for(int i = 1; i <= n; i ++)//线段树根节点从1开始 ,数组从1开始存 56 scanf("%d", &arr[i]); 57 build(1, n, 1); 58 for(int i = 1; i <= m; i ++) 59 { 60 ansmax = -inf; 61 ansmin = inf; 62 scanf("%d%d", &a, &b); 63 query(1, 1, n, a, b); 64 printf("%d\n", ansmax - ansmin); 65 } 66 return 0; 67 }