Description
给定序列
a
=
(
a
1
,
a
2
,
⋯
,
a
n
)
a=(a_1,a_2,\cdots,a_n)
a=(a1,a2,⋯,an),另有序列
h
h
h,初始时
h
=
a
h=a
h=a.
有
m
m
m 个操作分五种:
- add ( l , r , v ) \operatorname{add}(l,r,v) add(l,r,v):对每个 i ∈ [ l , r ] i\in[l,r] i∈[l,r] 执行 a i ← a i + v a_i\gets a_i+v ai←ai+v.
- subtract ( l , r , v ) \operatorname{subtract}(l,r,v) subtract(l,r,v):对每个 i ∈ [ l , r ] i\in[l,r] i∈[l,r] 执行 a i ← max ( 0 , a i − v ) a_i\gets \max(0, a_i-v) ai←max(0,ai−v).
- assign ( l , r , v ) \operatorname{assign}(l,r,v) assign(l,r,v):对每个 i ∈ [ l , r ] i\in[l,r] i∈[l,r] 执行 a i ← v a_i\gets v ai←v.
- get ( i ) \operatorname{get}(i) get(i):求 a i a_i ai.
- geth ( i ) \operatorname{geth}(i) geth(i):求 h i h_i hi.
每次修改后,对每个 i ∈ [ 1 , n ] i\in[1,n] i∈[1,n] 执行 h i ← max ( h i , a i ) h_i\gets \max(h_i,a_i) hi←max(hi,ai).
Limitations
1
≤
n
,
m
≤
5
×
1
0
5
1\le n,m\le 5\times 10^5
1≤n,m≤5×105
0
≤
a
i
,
v
≤
1
0
9
0\le a_i,v\le 10^9
0≤ai,v≤109
1
≤
l
,
r
,
i
≤
n
1\le l,r,i\le n
1≤l,r,i≤n
2
s
,
128
MB
2\text{s},128\text{MB}
2s,128MB
Solution
显然使用线段树.
由于带有
chmax
\operatorname{chmax}
chmax,每个节点维护标记
(
k
,
b
)
(k,b)
(k,b) 表示
x
x
x 变为
max
(
x
+
k
,
b
)
\max(x+k,b)
max(x+k,b).
那么三种修改可以如下表示:
- add \operatorname{add} add 操作: ( v , − ∞ ) (v,-\infty) (v,−∞).
- subtract \operatorname{subtract} subtract 操作: ( − v , 0 ) (-v,0) (−v,0).
- assign \operatorname{assign} assign 操作: ( − ∞ , v ) (-\infty,v) (−∞,v).
由于需要求
h
i
h_i
hi,还需要维护历史值的标记
(
hk
,
hb
)
(\textit{hk},\textit{hb})
(hk,hb).
考虑合并,画出图像(我画不好不献丑了),可得:
- ( k 0 , b 0 ) + ( k 1 , b 1 ) = ( k 0 + k 1 , max ( b 0 + k 1 , b 1 ) ) (k_0,b_0)+(k_1,b_1)=(k_0+k_1,\max(b_0+k_1,b_1)) (k0,b0)+(k1,b1)=(k0+k1,max(b0+k1,b1)).
- ( hk 0 , hb 0 ) + ( hk 1 , hb 1 ) = ( max ( hk 0 , k 0 + hk 1 ) , max ( hb 0 , hb 1 , b 0 + hk 1 ) ) (\textit{hk}_0,\textit{hb}_0)+(\textit{hk}_1,\textit{hb}_1)=(\max(\textit{hk}_0,k_0+\textit{hk}_1),\max(\textit{hb}_0,\textit{hb}_1,b_0+\textit{hk}_1)) (hk0,hb0)+(hk1,hb1)=(max(hk0,k0+hk1),max(hb0,hb1,b0+hk1)).
查询时直接取出点
i
i
i 的标记,计算即可.
注意幺元
e
=
(
0
,
−
∞
)
e=(0,-\infty)
e=(0,−∞),合并
k
k
k 时需要和
−
∞
-\infty
−∞ 取
max
\max
max,以及开 long long
.
Code
3 KB , 2.93 s , 45.11 MB (in total, C++ 20) 3\text{KB},2.93\text{s},45.11\text{MB}\;\texttt{(in total, C++ 20)} 3KB,2.93s,45.11MB(in total, C++ 20)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;
template<class T>
bool chmax(T &a, const T &b){
if(a < b){ a = b; return true; }
return false;
}
template<class T>
bool chmin(T &a, const T &b){
if(a > b){ a = b; return true; }
return false;
}
constexpr i64 inf = 2e18;
namespace seg_tree {
struct Tag {
i64 hk, hb, k, b;
inline Tag() : hk(0), hb(-inf), k(0), b(-inf) {}
inline Tag(i64 _hk, i64 _hb, i64 _k, i64 _b) : hk(_hk), hb(_hb), k(_k), b(_b) {}
inline void apply(const Tag& t) {
hk = max(hk, k + t.hk);
hb = max(hb, max(b + t.hk, t.hb));
k = max(k + t.k, -inf);
b = max(b + t.k, t.b);
}
inline i64 f(i64 x) { return max(k + x, b); }
inline i64 g(i64 x) { return max(hk + x, hb); }
};
struct Node {
int l, r;
Tag tag;
};
inline int ls(int u) { return 2 * u + 1; }
inline int rs(int u) { return 2 * u + 2; }
struct SegTree {
vector<Node> tr;
inline SegTree() {}
inline SegTree(int n) : tr(n << 1) { build(0, 0, n - 1); }
inline void pushdown(int u, int mid) {
tr[ls(mid)].tag.apply(tr[u].tag);
tr[rs(mid)].tag.apply(tr[u].tag);
tr[u].tag = Tag();
}
inline void build(int u, int l, int r) {
tr[u].l = l, tr[u].r = r, tr[u].tag = Tag();
if (l == r) return;
const int mid = (l + r) >> 1;
build(ls(mid), l, mid), build(rs(mid), mid + 1, r);
}
inline void update(int u, int l, int r, i64 k, i64 b) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u].tag.apply(Tag(k, b, k, b));
const int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u, mid);
if (l <= mid) update(ls(mid), l, r, k, b);
if (r > mid) update(rs(mid), l, r, k, b);
}
inline Tag get(int u, int p) {
if (tr[u].l == tr[u].r) return tr[u].tag;
const int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(u, mid);
if (p <= mid) return get(ls(mid), p);
else return get(rs(mid), p);
}
inline void range_add(int l, int r, i64 x) { update(0, l, r, x, -inf); }
inline void range_sub(int l, int r, i64 x) { update(0, l, r, -x, 0); }
inline void range_assign(int l, int r, i64 x) { update(0, l, r, -inf, x); }
inline Tag get(int p) { return get(0, p); }
};
}
using seg_tree::SegTree;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m;
scanf("%d %d", &n, &m);
vector<i64> a(n);
for (int i = 0; i < n; i++) scanf("%lld", &a[i]);
SegTree sgt(n);
for (int i = 0, op; i < m; i++) {
scanf("%d", &op);
if (op <= 3) {
int l, r; i64 k;
scanf("%d %d %lld", &l, &r, &k), l--, r--;
if (op == 1) sgt.range_add(l, r, k);
if (op == 2) sgt.range_sub(l, r, k);
if (op == 3) sgt.range_assign(l, r, k);
}
else {
int x; scanf("%d", &x), x--;
auto tag = sgt.get(x);
if (op == 4) printf("%lld\n", tag.f(a[x]));
if (op == 5) printf("%lld\n", tag.g(a[x]));
}
}
return 0;
}