题目链接:洛谷438D
知识点:线段树进阶,单点修改,区间和比较简单,重点取模(
思路,剪枝,当线段树中一区间的最大值比这个模数大的时候下层不用访问直接return;反之则一直向下访问当访问到叶子的时候更新取模。
要注意数的大小(大雾,又犯错QAQ
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
const int INF=0x3f3f3f3f;
int n,m,mx[N<<2],a[N]; //mx是区间最大值,a为叶子;
long long tr[N<<2];//区间和
void pushup(int p)
{
mx[p]=max(mx[p<<1],mx[p<<1|1]);
tr[p]=tr[p<<1]+tr[p<<1|1];
}
void build(int l,int r,int s)
{
if(l==r)
{
mx[s] = tr[s] = a[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,s<<1);
build(mid+1,r,s<<1|1);
pushup(s);
}
void update(int t,int x,int l,int r,int s)//单点修改;
{
if(l==r)
{
mx[s]=tr[s]=x;
return ;
}
int mid=(l+r)>>1;
if(t<=mid)
update(t,x,l,mid,s<<1);
else update(t,x,mid+1,r,s<<1|1);
pushup(s);
}
void getmod(int ll,int rr,int mod,int l,int r,int s)
{
if(mx[s]<mod)return;
if(l==r)
{
tr[s]=tr[s]%mod;
mx[s]=tr[s];
return;
}
int mid=(l+r)>>1;
if(ll<=mid)getmod(ll,rr,mod,l,mid,s<<1); //要取模的区间是否在范围内;
if(mid<rr)getmod(ll,rr,mod,mid+1,r,s<<1|1);
pushup(s);
}
long long getans(int ll,int rr,int l,int r,int s){
if(ll<=l&&rr>=r)return tr[s];
int mid=(l+r)>>1;
long long ans=0;
if(ll<=mid)ans = ans+getans(ll,rr,l,mid,s<<1);
if(rr>mid)ans = ans+getans(ll,rr,mid+1,r,s<<1|1);
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,n,1);
while(m--)
{
int opt;
scanf("%d",&opt);
if(opt==1)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%lld\n",getans(l,r,1,n,1));
}
else if(opt==2)
{
int l,r,temp;
scanf("%d%d%d",&l,&r,&temp);
getmod(l,r,temp,1,n,1);
}
else if(opt==3)
{
int x,y;
scanf("%d%d",&x,&y);
update(x,y,1,n,1);
}
}
return 0;
}