CF438D The Child and Sequence 线段树

你发现每一次有意义的取模至少会把一个数减半. 

所以如果没有赋值操作,每个数最多减半 $log$ 次,复杂度就是 $O(nlog^2n)$ 的. 

现在考虑赋值:依次最多只会增加 $O(logn)$ 的时间复杂度,所以复杂度还是 $O(nlog^2n)$ 的. 

code: 

#include <bits/stdc++.h> 
#define N 100005  
#define inf 12 
#define ll long long  
#define lson now<<1
#define rson now<<1|1 
#define setIO(s) freopen(s".in","r",stdin)    
using namespace std;
ll A[N],mx[N<<2];
ll sum[N<<2];  
void pushup(int l,int r,int now) 
{
    int mid=(l+r)>>1; 
    mx[now]=-inf, sum[now]=0; 
    if(l<=mid) sum[now]+=sum[lson], mx[now]=max(mx[now], mx[lson]); 
    if(r>mid)  sum[now]+=sum[rson], mx[now]=max(mx[now], mx[rson]);   
}
void build(int l,int r,int now) 
{
    if(l==r) 
    {
        sum[now]=mx[now]=A[l]; 
        return; 
    } 
    int mid=(l+r)>>1;    
    if(l<=mid) build(l,mid,lson); 
    if(r>mid)  build(mid+1,r,rson);  
    pushup(l,r,now); 
}   
ll query(int l,int r,int now,int L,int R) 
{
    if(l>=L&&r<=R) return sum[now];  
    ll tmp=0; 
    int mid=(l+r)>>1;  
    if(L<=mid) tmp+=query(l,mid,lson,L,R); 
    if(R>mid)  tmp+=query(mid+1,r,rson,L,R); 
    return tmp;     
}   
void update(int l,int r,int now,int L,int R,int mod) 
{
    if(mx[now]<mod) return;    
    if(l==r) 
    {
        sum[now]%=mod;                         
        mx[now]%=mod; 
        return; 
    } 
    int mid=(l+r)>>1;   
    if(L<=mid) update(l,mid,lson,L,R,mod); 
    if(R>mid)  update(mid+1,r,rson,L,R,mod); 
    pushup(l,r,now);      
}
void modify(int l,int r,int now,int p,int v) 
{
    if(l==r) 
    {
        sum[now]=mx[now]=1ll*v; 
        return; 
    } 
    int mid=(l+r)>>1; 
    if(p<=mid) modify(l,mid,lson,p,v); 
    else modify(mid+1,r,rson,p,v); 
    pushup(l,r,now);    
}
int main() 
{
    int i,j,n,m; 
    // setIO("input");    
    scanf("%d%d",&n,&m); 
    for(i=1;i<=n;++i) scanf("%lld",&A[i]);           
    build(1,n,1);    
    for(i=1;i<=m;++i) 
    {
        int op,l,r,x; 
        scanf("%d",&op);         
        if(op==1) 
        {
            scanf("%d%d",&l,&r); 
            printf("%lld\n",query(1,n,1,l,r)); 
        } 
        if(op==2) 
        {
            scanf("%d%d%d",&l,&r,&x);   
            update(1,n,1,l,r,x); 
        }  
        if(op==3) 
        {
            scanf("%d%d",&l,&x); 
            modify(1,n,1,l,x); 
        }
    }
    return 0; 
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值