线段树模板

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 }

 

以上是关于线段树模板的主要内容,如果未能解决你的问题,请参考以下文章

线段树模板整理

线段树模板总结

线段树模板

模板线段树-单点修改,区间查询

P3834 模板可持久化线段树 1(主席树)

模板 线段树(部分功能)