当前位置: 代码迷 >> 综合 >> [CodeVS 4927] 线段树练习5:两个Lazy Tag的线段树
  详细解决方案

[CodeVS 4927] 线段树练习5:两个Lazy Tag的线段树

热度:87   发布时间:2024-01-05 02:21:08.0

题意:维护一个长为n(n<=100000)的数列,支持区间加减、区间赋值两种修改,区间最小值、区间最大值、区间求和三种查询。

发现自己记不清线段树区间赋值怎么写了,而且感觉自己的写法和刘汝佳老师的蓝书上的代码不一样,于是做一做这道题。

刘汝佳老师定义赋值标记的优先级高于累加标记,于是同时有两个标记的时候需要先考虑赋值标记,再加上累加标记的值。我的写法略有不同。和CPU监控中的分析一样,加法、赋值混合运算,无论以何种顺序出现,均可化为零或一个加法、零或一个赋值。赋值标记覆盖累加标记,如果已经有赋值标记,再做加法,直接加到赋值标记上。赋值标记用一个布尔值即可,表示是否将min/max下传。

我把两种修改写一起,三种查询写一起,堆式存储。写在一起,代码会短,常数随之略有增加。

#include <cstdio>
#include <cctype>
#include <algorithm>
#define ALL 1, 1, n
using namespace std;
typedef long long ll;
const int MAX_N = 100000;
const ll inf = 1LL<<61;
ll x[MAX_N+1];struct Node {ll mn, mx, sum, a;bool b;
};struct Segment_Tree {enum op {ADD, SET};Node t[4*MAX_N];void maintain(int o){Node& self = t[o], & lc = t[o*2], & rc = t[o*2+1];self.mn = min(lc.mn, rc.mn);self.mx = max(lc.mx, rc.mx);self.sum = lc.sum + rc.sum;}void pushdown(Node u, Node& v, int w){ll x = u.mn, a = u.a;// SETif (u.b)v = (Node){x, x, x*w, 0, true};// ADDelse if (v.b)v = (Node){v.mn+a, v.mx+a, v.sum+w*a, 0, true};elsev = (Node){v.mn+a, v.mx+a, v.sum+w*a, v.a+a, false};}void pushdown(int o, int w){pushdown(t[o], t[o*2], (w+1)/2);pushdown(t[o], t[o*2+1], w/2);t[o].a = 0;t[o].b = false;}void build(ll A[], int o, int l, int r){if (l == r) {t[o] = (Node){A[l], A[l], A[l], 0, false};return;}int m = (l+r)/2;build(A, o*2, l, m);build(A, o*2+1, m+1, r);maintain(o);}   void modify(int x, int y, ll v, op c, int o, int l, int r){if (x <= l && r <= y) {if (c == ADD)pushdown((Node){
   0, 0, 0, v, false}, t[o], r-l+1);elsepushdown((Node){v, 0, 0, 0, true}, t[o], r-l+1);return;}pushdown(o, r-l+1);int m = (l+r)/2;if (x <= m)modify(x, y, v, c, o*2, l, m);if (y > m)modify(x, y, v, c, o*2+1, m+1, r);maintain(o);}void query(int x, int y, Node& d, int o, int l, int r){if (x <= l && r <= y) {d.mn = min(d.mn, t[o].mn);d.mx = max(d.mx, t[o].mx);d.sum += t[o].sum;return;}pushdown(o, r-l+1);int m = (l+r)/2;if (x <= m)query(x, y, d, o*2, l, m);if (y > m)query(x, y, d, o*2+1, m+1, r);maintain(o);}
} T;template<typename T>
inline void read(T& x)
{char c = getchar();x = 0;int s = 1;while (!isdigit(c)) {if (c == '-')s = -1;c = getchar();}while (isdigit(c)) {x = x*10 + c - '0';c = getchar();}x *= s;
}int main()
{int n, m;read(n), read(m);for (int i = 1; i <= n; ++i)read(x[i]);T.build(x, ALL);for (int i = 1; i <= m; ++i) {char s[4];ll x, y, z;scanf("%s", s), read(x), read(y);if (s[0] == 'a') {read(z);T.modify(x, y, z, Segment_Tree::ADD, ALL);} else if (s[0] == 's' && s[1] == 'e') {read(z);T.modify(x, y, z, Segment_Tree::SET, ALL);} else {Node r = (Node){inf, -inf, 0, 0, false};T.query(x, y, r, ALL);printf("%lld\n", s[0] == 's' ? r.sum : (s[1] == 'i' ? r.mn : r.mx));}}return 0;
}