題目大意:
給你一個序列,你要在這個序列上進行操作。
操作給定區間,對序列中這個區間的所有數求和。
操作給你區間,對 mod 。
操作給你兩個數個數將。
思路:
注意到,所以整體時間複雜度,也就是說你的所以操作時間複雜度不超過才過通過這個題。注意到區間求和,單點操作用線段樹都可以在做到,唯一有難度的就是操作對對區間所以數取模。首先考慮一個小小的剪枝,如果某個區間裏面的最大數都,那麼這個區間不用管了,因爲 mod 。當 mod 。稍微證明一下。
令 mod
那麼有
當 mod .
當 mod ,。
也就是說對於區間內的每個數,對它取mod,這個數至少會減低,那麼我們每次對這個數進行取模,這個數到的時間複雜度也無非就是,所以整體時間複雜度,帶兩個是可以過這道題的。
總結:
關於取模這裏,其實不用證明也很容易想到,因爲當 mod ,只有當這個時候才能取到最大值。它在其他地方的取模是對稱的,函數圖像大概是正態分佈的函數圖。對稱軸就是。
代碼:
#include<iostream>
using namespace std;
int n,m;
typedef long long int ll;
const int maxn = 1e5 + 10;
struct seg{
int l,r;
ll s,m;
seg(){s = 0,m = 0;}
seg(int a,int b):l(a),r(b){}
}tree[maxn << 2];
void build(int id,int l,int r){
if(l == r){
tree[id] = {l,r};
scanf("%d",&tree[id].s);
tree[id].m = tree[id].s;
return ;
}
int mid = l + r >> 1;
tree[id] = {l,r};
build(id << 1,l, mid);
build((id << 1) + 1,mid + 1,r);
tree[id].s = tree[id << 1].s + tree[(id << 1) + 1].s;
tree[id].m = max(tree[id << 1].m , tree[(id << 1) + 1].m);
}
void update(int id,int a,ll b){
if(tree[id].l == tree[id].r && tree[id].l == a){
tree[id].s = b;
tree[id].m = b;
return ;
}
int mid = tree[id].l + tree[id].r >> 1;
if(a <= mid)update(id << 1,a,b);
else update((id << 1) + 1,a,b);
tree[id].s = tree[id << 1].s + tree[(id << 1) + 1].s;
tree[id].m = max(tree[id << 1].m,tree[(id << 1) + 1].m);
}
void update2(int id,int l,int r,ll x){
if(tree[id].m < x)return;
if(tree[id].l == tree[id].r && tree[id].l >= l && tree[id].r <= r){
tree[id].s %= x;
tree[id].m = tree[id].s;
return ;
}
int mid = tree[id].l + tree[id].r >> 1;
if(r <= mid)update2(id << 1,l,r,x);
else if(l > mid)update2((id << 1) + 1,l,r,x);
else update2(id << 1,l,r,x),update2((id << 1) + 1,l,r,x);
tree[id].m = max(tree[id << 1].m,tree[(id << 1) + 1].m);
tree[id].s = tree[id << 1].s + tree[(id << 1) + 1].s;
}
ll query(int id,int l,int r){
if(tree[id].l >= l && tree[id].r <= r){
return tree[id].s;
}
ll ans = 0;
int mid = tree[id].l + tree[id].r >> 1;
if(r <= mid)return ans += query(id << 1,l,r);
else if(l > mid)return ans += query((id << 1) + 1,l,r);
else return ans += query(id << 1,l,r) + query((id << 1) + 1,l,r);
}
void solved(){
scanf("%d%d",&n,&m);
build(1,1,n);
int l,r,k,x;
while(m--){
int ins;scanf("%d",&ins);
if(1 == ins){
scanf("%d%d",&l,&r);
printf("%lld\n",query(1,l,r));
}
if(2 == ins){
scanf("%d%d%d",&l,&r,&x);
update2(1,l,r,x);
}
if(3 == ins){
scanf("%d%d",&k,&x);
update(1,k,x);
}
}
}
int main(){
solved();
return 0;
}