[CF438D]The Child and Sequence
题目大意:给定一个数列,三个操作:
- $1\;l\;r:$输出区间$[l,r]$的和
- $2\;l\;r\;x:$区间$[l,r]$对$x$取模
- $3\;p\;x:$把$p$的值修改成$x$
题解:线段树,发现对于取模操作,若模数大于被膜数,则不会有影响,可以通过维护最大值跳过,若是对有影响,那么这个数字一定至少会变成原来的一半,所以一个数最多更改$\log_2$次,可以承受。
卡点:我$\max$函数写成$\min$
C++ Code:
#include <cstdio>
#define maxn 100010
int s[maxn];
inline int max(int a, int b) {return a > b ? a : b;}
namespace Segment_Tree {
int n;
long long V[maxn << 2];
int M[maxn << 2];
inline update(int rt) {
M[rt] = max(M[rt << 1], M[rt << 1 | 1]);
V[rt] = V[rt << 1] + V[rt << 1 | 1];
}
void build(int rt = 1, int l = 1, int r = n) {
if (l == r) {
M[rt] = V[rt] = s[l];
return ;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
update(rt);
}
int L, R, p, x;
void ___add(int rt, int l, int r) {
if (l == r) {
V[rt] = M[rt] = x;
return ;
}
int mid = l + r >> 1;
if (p <= mid) ___add(rt << 1, l, mid);
else ___add(rt << 1 | 1, mid + 1, r);
update(rt);
}
inline void add(int pos, int X) {
p = pos, x = X;
___add(1, 1, n);
}
void __add(int rt, int l, int r) {
if (M[rt] < x) return ;
if (l == r) {
V[rt] = M[rt] = V[rt] % x;
return ;
}
int mid = l + r >> 1;
if (L <= mid) __add(rt << 1, l, mid);
if (R > mid) __add(rt << 1 | 1, mid + 1, r);
update(rt);
}
inline void add(int ll, int rr, int X) {
L = ll, R = rr, x = X;
__add(1, 1, n);
}
long long __ask(int rt, int l, int r) {
if (L <= l && R >= r) return V[rt];
int mid = l + r >> 1; long long ans = 0;
if (L <= mid) ans = __ask(rt << 1, l, mid);
if (R > mid) ans = ans + __ask(rt << 1 | 1, mid + 1, r);
return ans;
}
inline long long ask(int ll, int rr) {
L = ll, R = rr;
return __ask(1, 1, n);
}
}
using Segment_Tree::add;
using Segment_Tree::ask;
int n, m;
int main() {
scanf("%d%d", &n, &m); Segment_Tree::n = n;
for (int i = 1; i <= n; i++) scanf("%d", s + i);
Segment_Tree::build();
while (m --> 0) {
int op, l, r, val;
scanf("%d%d%d", &op, &l, &r);
if (op == 1) {
printf("%lld\n", ask(l, r));
} else if (op == 2) {
scanf("%d", &val);
add(l, r, val);
} else add(l, r);
}
return 0;
}

浙公网安备 33010602011771号