CF438D 题解

题目链接

前言

这是一棵区间膜线段树,与花神游历各国 很像,都是维护区间最值来优化暴力。

做法

线段树维护区间膜很麻烦,因为膜(mod)运算对于一个数减小得很快,所以考虑暴力区间修改。

但是要优化,不然会T飞掉。

怎么优化?

我们发现,有 $ x mod p < p$ 这个性质,所以当$ x \leq p$时,膜操作是无意义的。

于是,我们在暴力修改时,可以维护一个区间最大值,如果最大值是小于等于取膜的数,就不用递归下去。

然后就做完了。

Code 

#include<iostream>
#include<cstdio>
using namespace std;
#define int long long 
inline int read(){
    register int x=0,v=1,ch=getchar();
    while(!isdigit(ch)){if(ch=='-')v=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^'0');ch=getchar();}
    return x*v;
}
const int MAX=100005;
int n,m,a[MAX];
int op,x;

struct Seg{
    int sum,mx;
}tree[MAX<<2];
inline int Max(int a,int b){
    return a>b?a:b;
}
inline void pushup(int x){
    tree[x]=(Seg){tree[x<<1].sum+tree[x<<1|1].sum,Max(tree[x<<1].mx,tree[x<<1|1].mx)}; 
}
void build(int x,int l,int r){
    if(l==r){
        tree[x]=(Seg){a[l],a[l]}; 
        return ;
    }
    register int mid=l+r>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x);
}
void modify(int x,int l,int r,int s,int t,int v){
    if(l==r){
        tree[x]=(Seg){tree[x].sum%v,tree[x].mx%v};
        return ;
    }
    register int mid=l+r>>1;
    if(s<=mid&&tree[x<<1].mx>=v)modify(x<<1,l,mid,s,t,v);
    if(mid<t&&tree[x<<1|1].mx>=v)modify(x<<1|1,mid+1,r,s,t,v);
    pushup(x); 
} 
void change(int x,int l,int r,int s,int v){
    if(l==r){
        tree[x]=(Seg){v,v};
        return ;
    }
    register int mid=l+r>>1;
    if(s<=mid)change(x<<1,l,mid,s,v);
    else change(x<<1|1,mid+1,r,s,v);
    pushup(x);    
}
int query(int x,int l,int r,int s,int t){
    if(s<=l&&r<=t)return tree[x].sum;
    register int res=0,mid=l+r>>1;
    if(s<=mid)res+=query(x<<1,l,mid,s,t);
    if(mid<t)res+=query(x<<1|1,mid+1,r,s,t);
    return res; 
}
int l,r;
signed main(){
    n=read(),m=read();
    for(register int i=1;i<=n;++i)a[i]=read();
    build(1,1,n); 
    while(m--){
        op=read();
        l=read(),r=read();
        if(op==1){
            printf("%lld\n",query(1,1,n,l,r));
        }else if(op==2){
            x=read();
            modify(1,1,n,l,r,x);
        }else{
            change(1,1,n,l,r);
        }
    }
    return 0;
}#include<iostream>
#include<cstdio>
using namespace std;
#define int long long 
inline int read(){
    register int x=0,v=1,ch=getchar();
    while(!isdigit(ch)){if(ch=='-')v=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^'0');ch=getchar();}
    return x*v;
}
const int MAX=100005;
int n,m,a[MAX];
int op,x;

struct Seg{
    int sum,mx;
}tree[MAX<<2];
inline int Max(int a,int b){
    return a>b?a:b;
}
inline void pushup(int x){
    tree[x]=(Seg){tree[x<<1].sum+tree[x<<1|1].sum,Max(tree[x<<1].mx,tree[x<<1|1].mx)}; 
}
void build(int x,int l,int r){
    if(l==r){
        tree[x]=(Seg){a[l],a[l]}; 
        return ;
    }
    register int mid=l+r>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x);
}
void modify(int x,int l,int r,int s,int t,int v){
    if(l==r){
        tree[x]=(Seg){tree[x].sum%v,tree[x].mx%v};
        return ;
    }
    register int mid=l+r>>1;
    if(s<=mid&&tree[x<<1].mx>=v)modify(x<<1,l,mid,s,t,v);
    if(mid<t&&tree[x<<1|1].mx>=v)modify(x<<1|1,mid+1,r,s,t,v);
    pushup(x); 
} 
void change(int x,int l,int r,int s,int v){
    if(l==r){
        tree[x]=(Seg){v,v};
        return ;
    }
    register int mid=l+r>>1;
    if(s<=mid)change(x<<1,l,mid,s,v);
    else change(x<<1|1,mid+1,r,s,v);
    pushup(x);    
}
int query(int x,int l,int r,int s,int t){
    if(s<=l&&r<=t)return tree[x].sum;
    register int res=0,mid=l+r>>1;
    if(s<=mid)res+=query(x<<1,l,mid,s,t);
    if(mid<t)res+=query(x<<1|1,mid+1,r,s,t);
    return res; 
}
int l,r;
signed main(){
    n=read(),m=read();
    for(register int i=1;i<=n;++i)a[i]=read();
    build(1,1,n); 
    while(m--){
        op=read();
        l=read(),r=read();
        if(op==1){
            printf("%lld\n",query(1,1,n,l,r));
        }else if(op==2){
            x=read();
            modify(1,1,n,l,r,x);
        }else{
            change(1,1,n,l,r);
        }
    }
    return 0;
}

  

posted @ 2020-02-01 16:25  Lates  阅读(132)  评论(0)    收藏  举报