线段树对区间取模。
考试前就想写的题目QAQ,cxlove点了一下之后知道是什么回事了,先说下做法,暴力更新就行了,维护区间的最大值,每次把要取模的区间的最大值取出来,暴力更新,由于取模的性质可以保证每次取模之后至少比原数的一半还少,所以整体复杂度还是比较低的。
现在简单证明下a%b < a / 2:
首先我们先设b = ka , k属于(0,1]
1.若k <= 0.5 , 则根据%的运算符很容易得到a % b < 0.5a.
2.若k > 0.5,直接用减法可以替代取模运算,a -= b,容易得出a = (1 - k)a < 0.5a;
证毕。
贴代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
#define lson l,m,rt << 1
#define rson m + 1,r,rt << 1 | 1
#define lc rt << 1
#define rc rt << 1 | 1
using namespace std;
const int N = 100050;
int n,q;
struct Node
{
LL sum,maxVal;
int from;
}node[N << 2];
inline void pushUp(int rt){
node[rt].sum = node[lc].sum + node[rc].sum;
if(node[lc].maxVal < node[rc].maxVal){
node[rt].maxVal = node[rc].maxVal;
node[rt].from = node[rc].from;
}
else{
node[rt].maxVal = node[lc].maxVal;
node[rt].from = node[lc].from;
}
}
inline void build(int l,int r,int rt){
if(l == r){
scanf("%I64d",&node[rt].sum);
node[rt].maxVal = node[rt].sum;
node[rt].from = l;
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
pushUp(rt);
}
inline void assign(int p,int val,int l,int r,int rt){
// printf("val:%d\n",val);
if(l == r){
node[rt].sum = node[rt].maxVal = val;
return ;
}
int m = (l + r) >> 1;
if(p <= m) assign(p,val,lson);
else assign(p,val,rson);
pushUp(rt);
}
inline pair<int,int> queryMax(int L,int R,int l,int r,int rt){
if(L <= l && r <= R)
return make_pair(node[rt].maxVal,node[rt].from);
int m = (l + r) >> 1;
pair<int,int> ret = make_pair(-1,1);
if(L <= m) ret = queryMax(L,R,lson);
if(R > m) ret = max(ret,queryMax(L,R,rson));
return ret;
}
inline LL query(int L,int R,int l,int r,int rt){
if(L <= l && r <= R){
return node[rt].sum;
}
int m = (l + r) >> 1;
LL ret = 0;
if(L <= m) ret += query(L,R,lson);
if(R > m) ret += query(L,R,rson);
return ret;
}
int main(){
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
scanf("%d%d",&n,&q);
build(1,n,1);
while(q --){
int op;scanf("%d",&op);
if(op == 1){
int l,r;scanf("%d%d",&l,&r);
printf("%I64d\n",query(l,r,1,n,1));
}
else if (op == 2){
int l,r,x;scanf("%d%d%d",&l,&r,&x);
while(true){
pair<int,int> ret = queryMax(l,r,1,n,1);
// printf("l:%d r:%d max:%d from:%d new:%d\n",l,r,ret.first,ret.second,ret.first%x);
if(ret.first >= x){
assign(ret.second,ret.first % x,1,n,1);
}
else break;
}
}
else{
int k,x;scanf("%d%d",&k,&x);
assign(k,x,1,n,1);
}
}
return 0;
}