CodeForces 438 D.The Child and Sequence (线段树,区间取模)

题意:

长度为n的序列,m次操作
(1,l,r)求区间[l,r]的和
(2,l,r,x)区间[l,r]对x取模
(3,x,val)a[x]修改为val

输出每次操作1的结果

区间和可能爆int

思路:

操作1和3是线段树基本操作,主要问题在操作2,如果真的对每一个数都取模,肯定tle。

正确思路类似区间开方的一题,数值如果太小就不继续递归,这样剪枝之后就不会tle了。

线段树维护区间最值,取模操作的时候,如果最值比模数x小,则不需要进行操作,直接跳过。

ps:
取模操作一旦成功,那么这个数至少会减少一半,数字不断减少最值也会不断减少。
因此多次取模成功之后数字会变得很小,然后靠最值剪枝就行了(和区间开方思想基本一致)。

code:

#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define ll long long
const int maxm=1e5+5;
ll a[maxm<<2];//因为是存区间和,所以要开longlong
ll ma[maxm<<2];//存最值不用longlong
int n,m;
void pushup(int node){//取最值
    a[node]=a[node*2]+a[node*2+1];
    ma[node]=max(ma[node*2],ma[node*2+1]);
}
void build(int l,int r,int node){//建树
    if(l==r){
        scanf("%lld",&a[node]);
        ma[node]=a[node];
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,node*2);
    build(mid+1,r,node*2+1);
    pushup(node);
}
void change(int x,int val,int l,int r,int node){//单点修改
    if(l==r){
        ma[node]=a[node]=val;
        return ;
    }
    int mid=(l+r)/2;
    if(x<=mid){
        change(x,val,l,mid,node*2);
    }else{
        change(x,val,mid+1,r,node*2+1);
    }
    pushup(node);
}
void update(int x,int st,int ed,int l,int r,int node){//区间取模
    if(ma[node]<x)return ;//区间最值如果小于x,则不用继续递归
    if(l==r){
        ma[node]=(a[node]%=x);
        return ;
    }
    int mid=(l+r)/2;
    if(st<=mid){
        update(x,st,ed,l,mid,node*2);
    }
    if(ed>=mid+1){
        update(x,st,ed,mid+1,r,node*2+1);
    }
    pushup(node);
}
ll ask(int st,int ed,int l,int r,int node){//区间求和
    if(st<=l&&ed>=r){
        return a[node];
    }
    int mid=(l+r)/2;
    ll ans=0;
    if(st<=mid){
        ans+=ask(st,ed,l,mid,node*2);
    }
    if(ed>=mid+1){
        ans+=ask(st,ed,mid+1,r,node*2+1);
    }
    return ans;
}
signed main(){
    scanf("%d%d",&n,&m);
    build(1,n,1);
    while(m--){
        int d;
        scanf("%d",&d);
        if(d==1){//区间求和
            int l,r;
            scanf("%d%d",&l,&r);
            ll ans=ask(l,r,1,n,1);
            printf("%lld\n",ans);
        }else if(d==2){//区间取模
            int l,r,x;
            scanf("%d%d%d",&l,&r,&x);
            update(x,l,r,1,n,1);
        }else{//d==3,单点修改
            int x,val;
            scanf("%d%d",&x,&val);
            change(x,val,1,n,1);
        }
    }
    return 0;
}
发布了364 篇原创文章 · 获赞 26 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/103189485