序 列 序列 序列
正 解 部 分 \color{red}{正解部分} 正解部分
使用 线段树 维护
b
b
b, 初值为
−
b
i
-b_i
−bi, 每次修改时, 若一个位置上的值变为了
0
0
0, 则说明其会对答案产生新的贡献,
在外部使用 树状数组 将贡献计入答案, 然后将该位置的值 重置为
−
b
i
-b_i
−bi, 重置的时间复杂度是
O
(
log
N
)
O(\log N)
O(logN) .
考虑最坏情况, 每次操作
[
1
,
N
]
[1, N]
[1,N],
这样
b
i
=
1
b_i=1
bi=1 的位置最多重置
N
N
N 次
b
i
=
2
b_i=2
bi=2 最多重置
N
2
\frac{N}{2}
2N 次,
b
i
=
3
b_i=3
bi=3 最多 …
所以总共需要 重置 O ( N log N ) O(N \log N) O(NlogN) 次, 总时间复杂度 O ( N log 2 N ) O(N \log^2 N) O(Nlog2N) .
实 现 部 分 \color{red}{实现部分} 实现部分
重置 可以在 修改 时 使用 u p d a t e ( ) update() update() 实现 .
#include<bits/stdc++.h>
#define reg register
#define fi first
#define se second
typedef std::pair<int, int> pr;
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int maxn = 100005;
const int inf = 0x3f3f3f3f;
int N;
int M;
int Tmp_1;
int B[maxn];
struct Bit_Tree{
int v[maxn], lim;
void Add(int k, int x){ while(k<=lim)v[k]+=x,k+=k&-k; }
int Query(int k){ if(k<=0)return 0; int s=0; while(k)s+=v[k],k-=k&-k; return s; }
} bit_t;
struct Segment_Tree{
struct Node{ int l, r, t, max_v, id; } T[maxn << 2];
void Push_down(const int &k){
T[k].max_v += T[k].t;
if(T[k].l == T[k].r) return T[k].t = 0, void();
T[k<<1].t += T[k].t, T[k<<1|1].t += T[k].t, T[k].t = 0;
}
void Push_up(const int &k){
if(T[k<<1].t) Push_down(k<<1);
if(T[k<<1|1].t) Push_down(k<<1|1);
T[k].max_v = std::max(T[k<<1].max_v, T[k<<1|1].max_v);
if(T[k<<1].max_v == T[k].max_v) T[k].id = k<<1;
else T[k].id = k<<1|1;
}
void Build(int k, int l, int r){
T[k].l = l, T[k].r = r; if(l == r) return T[k].max_v = B[l], T[k].id = k, void();
int mid = l+r >> 1; Build(k<<1, l, mid), Build(k<<1|1, mid+1, r); Push_up(k);
}
void update(int k){
int l = T[k].l, r = T[k].r;
if(T[k].t) Push_down(k);
if(l == r) return bit_t.Add(l, 1), T[k].max_v=B[l], void();
update(T[k].id); Push_up(k);
}
void Modify(int k, const int &ql, const int &qr, const int &aim){
int l = T[k].l, r = T[k].r;
if(T[k].t) Push_down(k);
if(r < ql || l > qr) return ;
if(ql <= l && r <= qr){
T[k].t += aim, Push_down(k);
while(!T[k].max_v) update(k);
return ;
}
Modify(k<<1, ql, qr, aim), Modify(k<<1|1, ql, qr, aim); Push_up(k);
}
int Query(int k, const int &ql, const int &qr){
int l = T[k].l, r = T[k].r;
if(T[k].t) Push_down(k);
if(r < ql || l > qr) return -inf;
if(ql <= l && r <= qr) return T[k].max_v;
return std::max(Query(k<<1, ql, qr), Query(k<<1|1, ql, qr));
}
} seg_t;
int main(){
N = read(), M = read();
for(reg int i = 1; i <= N; i ++) B[i] = -read();
seg_t.Build(1, 1, N); bit_t.lim = N;
for(reg int i = 1; i <= M; i ++){
int opt = read(), l = read(), r = read();
if(opt == 2) printf("%d\n", bit_t.Query(r) - bit_t.Query(l-1));
else seg_t.Modify(1, l, r, 1);
}
return 0;
}