线段树+Lazy标记(我的模版)

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 typedef unsigned long long ull;
  5 #define INF 0X3f3f3f3f
  6 const ll MAXN = 2e5 + 7;
  7 const ll MOD = 1e9 + 7;
  8 ll a[MAXN];
  9 struct node
 10 {
 11     int left, right; //区间端点
 12     ll max, sum;     //看题目要求
 13     ll lazy;
 14     void update(ll x)
 15     {
 16         sum += (right - left + 1) * x;
 17         lazy += x;
 18     }
 19 } tree[MAXN << 2];
 20 //建树,开四倍
 21 void push_up(int x)
 22 {
 23     tree[x].sum = tree[x << 1].sum + tree[x << 1 | 1].sum;
 24     tree[x].max = max(tree[x << 1].max, tree[x << 1 | 1].max);
 25 }
 26 void push_down(int x)
 27 {
 28     ll lazeval = tree[x].lazy;
 29     if (lazeval)
 30     {
 31         tree[x << 1].update(lazeval);
 32         tree[x << 1 | 1].update(lazeval);
 33         tree[x].lazy = 0;
 34     }
 35 }
 36 //若原数组从a[1]~a[n],调用build(1,1,n);
 37 void build(int x, int l, int r)
 38 {
 39     tree[x].left = l;
 40     tree[x].right = r;
 41     tree[x].sum = tree[x].lazy = 0;
 42     if (l == r) //若到达叶节点
 43     {
 44         tree[x].sum = a[l]; //存储A数组的值
 45         tree[x].max = a[l];
 46     }
 47     else
 48     {
 49         int mid = (l + r) / 2;
 50         build(x << 1, l, mid);
 51         build(x << 1 | 1, mid + 1, r);
 52         push_up(x);
 53     }
 54     return;
 55 }
 56 //update(1,l,r,v)
 57 void update(int x, int l, int r, ll v) //区间更新
 58 {
 59     int L = tree[x].left, R = tree[x].right;
 60     if (l <= L && R <= r)
 61     {
 62         tree[x].update(v);
 63         tree[x].max += v;
 64     }
 65     else
 66     {
 67         push_down(x);
 68         int mid = (L + R) / 2;
 69         if (mid >= l)
 70             update(x << 1, l, r, v);
 71         if (r > mid)
 72             update(x << 1 | 1, l, r, v);
 73         push_up(x);
 74     }
 75 }
 76 //单点更新,更新pos点,调用add(1,pos,v)
 77 void add(int x, int pos, ll v) //当前更新的节点的编号为id(一般是以1为第一个编号)。pos为需要更新的点的位置,v为修改的值的大小
 78 {
 79     
 80     int L = tree[x].left, R = tree[x].right;
 81     if (L == pos && R == pos) //左右端点均和pos相等,说明找到了pos所在的叶子节点
 82     {
 83         tree[x].sum += v;
 84         tree[x].max += v;
 85         return; //找到了叶子节点就不需要在向下寻找了
 86     }
 87     int mid = (L + R) / 2;
 88     if (pos <= mid)
 89         add(x << 1, pos, v);
 90     else
 91         add(x << 1 | 1, pos, v); //寻找k所在的子区间
 92     push_up(x);                  //向上更新
 93 }
 94 //调用query_sum(1,l,r)即可查询[l,r]区间内元素的总和
 95 //区间查询
 96 ll query_sum(int x, int l, int r)
 97 {
 98     int L = tree[x].left, R = tree[x].right;
 99     if (l <= L && R <= r)
100         return tree[x].sum;
101     else
102     {
103         push_down(x);
104         ll ans = 0;
105         int mid = (L + R) / 2;
106         if (mid >= l)
107             ans += query_sum(x << 1, l, r);
108         if (r > mid)
109             ans += query_sum(x << 1 | 1, l, r);
110         push_up(x);
111         return ans;
112     }
113 }
114 //调用query_max(1,l,r)即可求[l,r]区间内元素的最大值
115 ll query_max(int x, int l, int r)
116 {
117     int L = tree[x].left, R = tree[x].right;
118     if (l == L && R == r)
119         return tree[x].max;
120     else
121     {
122         push_down(x);
123         int mid = (L + R) / 2;
124         if (r <= mid)
125             return query_max(x << 1, l, r);
126         else if (l > mid)
127             return query_max(x << 1 | 1, l, r);
128         else
129             return max(query_max(x << 1, l, mid), query_max(x << 1 | 1, mid+1, r));
130     }
131 }
132 int main()
133 {
134     ll n, m;
135     while (scanf("%lld%lld", &n, &m) != EOF)
136     {
137         for (int i = 1; i <= n; i++)
138             scanf("%lld", &a[i]);
139         build(1, 1, n);
140         getchar();
141         while (m--)
142         {
143             int l, r;
144             char que;
145             scanf("%c %d %d", &que, &l, &r);
146             getchar();
147             if (que == 'Q')
148                 printf("%lld\n", query_max(1, l, r));
149             else if (que == 'U')
150                 update(1, l,l, r - a[l]),a[l]=r;
151         }
152     }
153     return 0;
154 }

转载于:https://www.cnblogs.com/graytido/p/10745106.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值