线段树模板
Posted alexlins
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树模板相关的知识,希望对你有一定的参考价值。
以下为为求区间和,求区间最大值,最小值模板
题目以 敌兵布阵
HDU - 1166 为例子
1 #include <iostream> 2 #include <algorithm> 3 #include <string.h> 4 #include <cstdio> 5 #include <string> 6 #include <cmath> 7 #include <vector> 8 #include <stack> 9 #include <queue> 10 #include <stack> 11 #include <list> 12 #include <map> 13 #include <set> 14 //#include <unordered_map> 15 #define Fbo friend bool operator < (node a, node b) 16 #define mem(a, b) memset(a, b, sizeof(a)) 17 #define FOR(a, b, c) for(int a = b; a <= c; a++) 18 #define RFOR(a,b, c) for(int a = b; a >= c; a--) 19 #define off ios::sync_with_stdio(0) 20 bool check1(int a) { return (a & (a - 1)) == 0 ? true : false; } 21 22 using namespace std; 23 typedef pair<int, int> pii; 24 typedef long long ll; 25 const int INF = 0x3f3f3f3f; 26 const int mod = 1e9 + 7; 27 const int Maxn = 2e5 + 5; 28 const double pi = acos(-1.0); 29 const double eps = 1e-8; 30 31 ll a[Maxn]; 32 33 struct node { 34 ll l, r;//区间[l,r] 35 ll add;//区间的延时标记 36 ll sum;//区间和 37 int maxn; //区间最大值 38 int minn; //区间最小值 39 }tree[Maxn * 4 + 5];//一定要开到4倍多的空间 40 41 void pushup(ll rt) { //向上更新 42 tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum; 43 tree[rt].maxn = max(tree[rt << 1].maxn, tree[rt << 1 | 1].maxn); 44 tree[rt].minn = min(tree[rt << 1].minn, tree[rt << 1 | 1].minn); 45 } 46 void pushdown(ll rt) {//向下更新 47 if (tree[rt].add) { //若有标记,则讲标记向下移动一层 48 tree[rt << 1].add += tree[rt].add; 49 tree[rt << 1 | 1].add += tree[rt].add; 50 tree[rt << 1].maxn += tree[rt].add; 51 tree[rt << 1 | 1].maxn += tree[rt].add; 52 tree[rt << 1].minn += tree[rt].add; 53 tree[rt << 1 | 1].minn += tree[rt].add; 54 tree[rt << 1].sum += (tree[rt << 1].r - tree[rt << 1].l + 1) * tree[rt].add; 55 tree[rt << 1 | 1].sum += (tree[rt << 1 | 1].r - tree[rt << 1 | 1].l + 1) * tree[rt].add; 56 tree[rt].add = 0; //取消本层标记 57 58 } 59 } 60 void BuildTree(ll l, ll r, ll rt) { 61 tree[rt].l = l; 62 tree[rt].r = r; 63 tree[rt].add = 0;//刚开始一定要清0 64 tree[rt].sum = r - l + 1; //更新结点rt的值 65 if (l == r) { 66 //此行根据题意看情况填什么————- 67 tree[rt].sum = a[l]; 68 //———————————————— 69 return; 70 } 71 ll mid = (l + r) >> 1; 72 BuildTree(l, mid, rt << 1); //递归左子树 73 BuildTree(mid + 1, r, (rt << 1) + 1); //递归右子树 74 pushup(rt);//向上更新 75 } 76 void updata(ll l, ll r, ll val, ll rt) { //root为结点 区间更新 77 // cout << l << " " << tree[rt].l << "----" << r << " " << tree[rt].r << endl; 验证路径 78 if (l <= tree[rt].l && r >= tree[rt].r) { 79 tree[rt].sum += (tree[rt].r - tree[rt].l + 1) * val; 80 tree[rt].minn += val; //求区间最大值时应改为 tree[rt].minn = val 81 tree[rt].maxn += val; //求区间最小值时应改为 tree[rt].maxn += val 82 tree[rt].add += val;//延时标记 83 return; 84 } 85 pushdown(rt); 86 ll mid = (tree[rt].l + tree[rt].r) >> 1; 87 if (l <= mid) { 88 updata(l, r, val, rt << 1); 89 } 90 if (r > mid) { 91 updata(l, r, val, rt << 1 | 1); 92 } 93 pushup(rt);//向上更新 94 } 95 96 ll querySum(ll l, ll r, ll rt) { //区间求和 97 if (l <= tree[rt].l && r >= tree[rt].r) { 98 return tree[rt].sum; 99 } 100 pushdown(rt); 101 ll mid = (tree[rt].l + tree[rt].r) >> 1; 102 ll ans = 0; 103 ll Max = 0; 104 ll Min = INF; 105 if (l <= mid) { 106 ans += querySum(l, r, rt << 1); 107 } 108 if (r > mid) { 109 ans += querySum(l, r, rt << 1 | 1); 110 } 111 return ans; 112 } 113 114 ll queryMin(ll l, ll r, ll rt) { 115 if (l <= tree[rt].l && r >= tree[rt].r) { 116 return tree[rt].minn; 117 } 118 pushdown(rt); 119 ll mid = (tree[rt].l + tree[rt].r) >> 1; 120 ll ans = 0; 121 ll Max = 0; 122 ll Min = INF; 123 if (l <= mid) { 124 Min = min(queryMin(l, r, rt << 1), Min); 125 } 126 if (r > mid) { 127 Min = min(queryMin(l, r, rt << 1 | 1), Min); 128 } 129 return Min; 130 } 131 ll queryMax(ll l, ll r, ll rt) { 132 if (l <= tree[rt].l && r >= tree[rt].r) { 133 return tree[rt].maxn; 134 } 135 pushdown(rt); 136 ll mid = (tree[rt].l + tree[rt].r) >> 1; 137 ll ans = 0; 138 ll Max = 0; 139 ll Min = INF; 140 if (l <= mid) { 141 Max = max(queryMax(l, r, rt << 1), Max); 142 } 143 if (r > mid) { 144 Max = max(queryMax(l, r, rt << 1 | 1), Max); 145 } 146 147 return Max; 148 } 149 150 int main() 151 { 152 ll t, n, x, y; 153 scanf("%lld", &t); 154 FOR(i, 1, t) { 155 string s; 156 scanf("%lld", &n); 157 printf("Case %d: ", i); 158 FOR(j, 1, n)scanf("%d", &a[j]); 159 BuildTree(1, n, 1); 160 while (1) { 161 cin >> s; 162 if (s == "End") break; 163 scanf("%lld%lld", &x, &y); 164 if (s == "Query") cout << querySum(x, y, 1) << endl; 165 if (s == "Add") updata(x, x, y, 1);//[a,a]的元素更新为b 166 if (s == "Sub") updata(x, x, -y, 1); 167 } 168 } 169 return 0; 170 }
以上是关于线段树模板的主要内容,如果未能解决你的问题,请参考以下文章