学习线段树的第一题。
是的,区间树这个名字更为形象。
线段树适用于和区间统计有关的问题。比如某些数据
可以按区间进行划分,按区间动态进行修改,而且还
需要按区间多次进行查询,那么使用线段树可以达到
较快查询速度。
下面的代码是用数组来表示树结构的。
1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 using namespace std; 6 7 const int INF = 0xffffff0; 8 int minV = INF; 9 int maxV = -INF; 10 11 struct Node 12 { 13 int L; 14 int R; 15 int minV, maxV; 16 int Mid() 17 { 18 return (L + R) / 2; 19 } 20 }; 21 Node tree[800000 + 10]; 22 23 void BuildTree(int root, int L, int R) 24 { 25 tree[root].L = L; 26 tree[root].R = R; 27 tree[root].minV = INF; 28 tree[root].maxV = -INF; 29 if(L != R) 30 { 31 BuildTree(root * 2 + 1, L, (L+R)/2); 32 BuildTree(root * 2 + 2, (L+R)/2 + 1, R); 33 } 34 } 35 36 void Insert(int root, int i, int v) 37 {//插入第i个值为v的数 38 if(tree[root].L == tree[root].R) 39 { 40 tree[root].minV = tree[root].maxV = v; 41 return; 42 } 43 tree[root].minV = min(tree[root].minV, v); 44 tree[root].maxV = max(tree[root].maxV, v); 45 if(i <= tree[root].Mid()) 46 Insert(root*2 + 1, i, v); 47 else 48 Insert(root*2 + 2, i, v); 49 } 50 51 void Query(int root, int s, int e) 52 {//查询区间[s,e]上的最大值和最小值然后存放到全局变量里 53 if(tree[root].minV >= minV && tree[root].maxV <= maxV) 54 return; 55 if(tree[root].L == s && tree[root].R == e) 56 { 57 minV = min(tree[root].minV, minV); 58 maxV = max(tree[root].maxV, maxV); 59 return; 60 } 61 if(e <= tree[root].Mid()) 62 Query(root*2 + 1, s, e); 63 else if(s > tree[root].Mid()) 64 Query(root*2 + 2, s, e); 65 else 66 { 67 Query(root*2 + 1, s, tree[root].Mid()); 68 Query(root*2 + 2, tree[root].Mid()+1, e); 69 } 70 } 71 72 int main(void) 73 { 74 #ifdef LOCAL 75 freopen("3264in.txt", "r", stdin); 76 #endif 77 78 int n, q; 79 scanf("%d%d", &n, &q); 80 BuildTree(0, 1, n); 81 for (int i = 1; i <= n; ++i) 82 { 83 int j; 84 scanf("%d", &j); 85 Insert(0, i, j); 86 } 87 for (int i = 0; i < q; ++i) 88 { 89 int s, e; 90 scanf("%d%d", &s, &e); 91 minV = INF; 92 maxV = -INF; 93 Query(0, s, e); 94 printf("%d\n", maxV - minV); 95 } 96 return 0; 97 }