题目概述
给你一串数字,支持一下几种操作
- 区间和查询
- 区间取模
- 单点修改
题目链接
分析
显然是线段树,应为没有区间修改这类的操作,我们于是省去了一个懒标签和pushdown的操作,关键是如何取模,这里维护了一个区间最大值,如果最大值小于模的化直接返回,相当于做了一些局部优化,数字还挺多,建议快读。
代码
#include <iostream>
#include <algorithm>
#include <cctype>
#include <cstdio>
#define mid (l + r >> 1)
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, q;
inline int read(){
int x = 0, op = 1;
char ch = getchar();
while (!isdigit(ch)){
if (ch == '-') op = -1;
ch = getchar();
}
while (isdigit(ch)){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * op;
}
ll sum[N << 2], Max[N << 2];
inline void push_up(int i){
sum[i] = sum[i << 1] + sum[i << 1|1];
Max[i] = max(Max[i << 1], Max[i << 1|1]);
}
inline void buildTree(int i, int l, int r){
if (l == r){
sum[i] = Max[i] = read();
return;
}
buildTree(i << 1, l, mid);
buildTree(i << 1|1, mid + 1, r);
push_up(i);
}
inline void modify_point(int i, int l, int r, int pos, ll val){
if (l == r){
sum[i] = Max[i] = val;
return;
}
if (pos <= mid)
modify_point(i << 1, l, mid, pos, val);
else
modify_point(i << 1|1, mid + 1, r, pos, val);
push_up(i);
}
inline void modify_mod(int i, int l, int r, int crtl, int crtr, int mod){
if (Max[i] < mod)
return;
if (l == r){
sum[i] %= mod;
Max[i] %= mod;
return;
}
if (mid >= crtl)
modify_mod(i << 1, l, mid, crtl, crtr, mod);
if (mid < crtr)
modify_mod(i << 1|1, mid + 1, r, crtl ,crtr, mod);
push_up(i);
}
inline ll query_interval(int i, int l, int r, int crtl, int crtr){
if (l > crtr || r < crtl)
return 0;
if (l >= crtl && r <= crtr)
return sum[i];
ll ans = 0;
if (mid >= crtl)
ans += query_interval(i << 1, l, mid, crtl, crtr);
if (mid < crtr)
ans += query_interval(i << 1|1, mid + 1, r, crtl, crtr);
return ans;
}
int main() {
n = read(), q = read();
buildTree(1, 1, n);
int op, a, b, c;
while (q--){
op = read();
a = read(), b = read();
if (op == 1){
printf("%lld\n", query_interval(1, 1, n, a, b));
}else if (op == 2){
c = read();
modify_mod(1, 1, n, a, b, c);
}else{
modify_point(1, 1, n, a, b);
}
}
return 0;
}