bzoj1798: [Ahoi2009]Seq 维护序列seq

本文详细介绍了一种高效的数据结构——线段树,并提供了一个具体的实现案例。文章讲解了线段树的基本概念、如何通过打标记的方式进行区间更新操作,包括加法和乘法更新,以及如何查询区间和。此外,还提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门
裸的线段树,每个节点打标记add和mul,注意下传即可。

#include<cmath>
#include<cstdio>  
#include<cstdlib>
#include<cstring>  
#include<iostream>
#include<algorithm>
#define ll long long   
using namespace std;  
const int N=100010;  
struct node{  
    int L,R;  
    ll sum,add,mul;  
}t[N*4];  
int a[N],mo,n,m;  
void pushup(int p){  
    t[p].sum=(t[p<<1].sum+t[p<<1|1].sum)%mo;  
}  
void update1(int p,ll d){  
    int len=t[p].R-t[p].L+1;  
    t[p].sum=(t[p].sum+d*len%mo)%mo;  
    t[p].add=(t[p].add+d)%mo;  
}  
void update2(int p,ll d){  
    t[p].sum=(t[p].sum*d)%mo;  
    t[p].add=(t[p].add*d)%mo;  
    t[p].mul=(t[p].mul*d)%mo;  
}  
void pushdown(int p){  
    update2(p<<1,t[p].mul);  
    update2(p<<1|1,t[p].mul);  
    t[p].mul=1;  
    update1(p<<1,t[p].add);  
    update1(p<<1|1,t[p].add);  
    t[p].add=0;  
}  
void build(int p,int L,int R){  
    if(L==R){  
        t[p].L=t[p].R=L;  
        t[p].sum=a[L];  
        t[p].add=0;  
        t[p].mul=1;  
        return;  
    }  
    int mid=L+R>>1;  
    build(p<<1,L,mid);  
    build(p<<1|1,mid+1,R);  
    t[p].L=L;  
    t[p].R=R;  
    t[p].mul=1;  
    t[p].add=0;  
    pushup(p);  
}  
void add(int p,int L,int R,int d){  
    int n_L=t[p].L;  
    int n_R=t[p].R;  
    if(L<=n_L && n_R<=R){  
        update1(p,d);  
        return;  
    }  
    pushdown(p);  
    int mid=n_L+n_R>>1;  
    if(L<=mid)add(p<<1,L,R,d);  
    if(mid<R)add(p<<1|1,L,R,d);  
    pushup(p);  
}  
void mul(int p,int L,int R,int d){  
    int n_L=t[p].L;  
    int n_R=t[p].R;  
    if(L<=n_L && n_R<=R){  
        update2(p,d);  
        return;  
    }  
    pushdown(p);  
    int mid=n_L+n_R>>1;  
    if(L<=mid)mul(p<<1,L,R,d);  
    if(mid<R)mul(p<<1|1,L,R,d);  
    pushup(p);  
}  
int sum(int p,int L,int R){  
    int n_L=t[p].L;  
    int n_R=t[p].R;  
    if(L<=n_L && n_R<=R)return t[p].sum;  
    pushdown(p);  
    int mid=n_L+n_R>>1;  
    ll ret=0;  
    if(L<=mid)ret=(ret+sum(p<<1,L,R))%mo;  
    if(mid<R) ret=(ret+sum(p<<1|1,L,R))%mo;  
    return ret;  
}  
int main(){  
    scanf("%d%d",&n,&mo);  
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);  
    build(1,1,n);   
    scanf("%d",&m);  
    for(int i=1;i<=m;i++){  
        int fg,L,R,d;  
        scanf("%d",&fg);  
        switch(fg){  
            case 1:{  
                scanf("%d%d%d",&L,&R,&d);  
                mul(1,L,R,d);  
                break;  
            }  
            case 2:{  
                scanf("%d%d%d",&L,&R,&d);  
                add(1,L,R,d);  
                break;  
            }  
            case 3:{  
                scanf("%d%d",&L,&R);  
                printf("%d\n",sum(1,L,R));  
                break;  
            }  
        }  
    }  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值