给出一个长度为n的序列,给出q次操作。
操作分为三种:
1:1,l,r。查询「l,r」的区间和。
2:2,l,r,mod。区间「l,r」全体模mod。
3:3,a,b。将a点的值更改为b。
区间更新的线段树,有一个剪枝不太好想到,就是记录子树的Max,当对区间取模的时候,如果Max < mod的话,直接跳过。
AC代码:
#include <stdio.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 5e5+100;
struct NODE
{
int l,r;
ll sum,Max;
int mid(){
return (l+r)/2;
}
}node[N<<2];
inline void PushUp(int x){
node[x].Max = max(node[x<<1].Max,node[x<<1|1].Max);
node[x].sum = node[x<<1].sum + node[x<<1|1].sum;
}
void BuildTree(int l,int r,int x){
node[x].l = l;
node[x].r = r;
if(l == r){
scanf("%d",&node[x].sum);
node[x].Max = node[x].sum;
return;
}
int mid = (l+r)/2;
BuildTree(l,mid,x<<1);
BuildTree(mid+1,r,x<<1|1);
PushUp(x);
}
inline void Updata(int c,int l,int r,int x){
if(node[x].l >= l && node[x].r <= r){
if(node[x].Max < c) return;
if(node[x].l == node[x].r){
node[x].sum %= c;
node[x].Max %= c;
return;
}
}
int mid = node[x].mid();
if(r <= mid){
Updata(c,l,r,x<<1);
}
else if(l > mid){
Updata(c,l,r,x<<1|1);
}
else{
Updata(c,l,mid,x<<1);
Updata(c,mid+1,r,x<<1|1);
}
PushUp(x);
}
inline void change(int c,int loc,int x){
if(node[x].l == node[x].r){
node[x].sum = c;
node[x].Max = c;
return;
}
int mid = node[x].mid();
if(loc <= mid){
change(c,loc,x<<1);
}
else{
change(c,loc,x<<1|1);
}
PushUp(x);
}
inline ll Query(int l,int r,int x){
if(node[x].l == l && node[x].r == r){
return node[x].sum;
}
ll res = 0;
int mid = node[x].mid();
if(r <= mid){
res += Query(l,r,x<<1);
}
else if(l > mid){
res += Query(l,r,x<<1|1);
}
else{
res += Query(l,mid,x<<1);
res += Query(mid+1,r,x<<1|1);
}
return res;
}
int main(int argc, char const *argv[])
{
int n,q;
int op,a,b,c;
scanf("%d %d",&n,&q);
BuildTree(1,n,1);
while(q--){
scanf("%d",&op);
if(op == 1){
scanf("%d %d",&a,&b);
printf("%lld\n", Query(a,b,1));
}
else if(op == 2){
scanf("%d %d %d",&a,&b,&c);
Updata(c,a,b,1);
}
else{
scanf("%d %d",&a,&b);
change(b,a,1);
}
}
return 0;
}