CF438D The Child and Sequence(线段树区间暴力取模)
CF438D The Child and Sequence
同一个思路AC四道题太爽了
题目大意:
区间求和,区间取模,单点修改。
分析:
难点在于区间取模很难实现标记下传以及合并。
思路和线段树区间暴力开根类似。维护一个区间最大值。当要取模的区间最大值比模数小时,给这个区间取模相当于没有取模;否则即使要取模,区间中的每个数都最多只会被操作 \(O(log(x))\) 次,所以单点暴力取模不会超时。
代码:
#include<bits/stdc++.h>
#define int long long
#define MAXN 100086
using namespace std;
int a[MAXN];
inline int read() {
int x = 0, fh = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
fh = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * fh;
}
struct T{
int l,r,val,maxn;
}t[MAXN*4];
int n,m;
void update(int node){
t[node].val=t[node<<1].val+t[node<<1|1].val;
t[node].maxn=max(t[node<<1].maxn,t[node<<1|1].maxn);
}
void build(int l,int r,int node){
t[node].l=l;
t[node].r=r;
if(l==r){
t[node].val=a[l];
t[node].maxn=a[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,node<<1);
build(mid+1,r,node<<1|1);
update(node);
}
void change(int l,int r,int node,int p,int k){
if(l==r){
t[node].val=k;
t[node].maxn=k;
return ;
}
int mid=(l+r)>>1;
int ans=0;
if(p<=mid)change(l,mid,node<<1,p,k);
else change(mid+1,r,node<<1|1,p,k);
update(node);
}
int ask(int l,int r,int node,int x,int y){
if(x<=l&&r<=y){
return t[node].val;
}
int ans=0;
int mid=(l+r)>>1;
if(x<=mid)ans+=ask(l,mid,node<<1,x,y);
if(y>mid)ans+=ask(mid+1,r,node<<1|1,x,y);
return ans;
}
void change_mod(int l,int r,int node,int x,int y,int p){
if(t[node].maxn<p)return ;
if(l==r){
t[node].val%=p;
t[node].maxn%=p;
return ;
}
int mid=(l+r)>>1;
if(x<=mid)change_mod(l,mid,node<<1,x,y,p);
if(y>mid)change_mod(mid+1,r,node<<1|1,x,y,p);
update(node);
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,n,1);
int op,x,y,z,k,p;
for(int i=1;i<=m;i++){
cin>>op>>x>>y;
if(op==1){
cout<<ask(1,n,1,x,y)<<'\n';
}
if(op==2){
cin>>z;
change_mod(1,n,1,x,y,z);
}
if(op==3){
change(1,n,1,x,y);
}
}
return 0;
}