线段树+树状数组模板

建树+单点更新+区间更新+区间查询 

const int maxn=300010;
int a[maxn],ans[maxn<<2],lazy[maxn<<2];
//a为原序列,ans模拟线段树维护区间和,lazy[]为懒惰标记
void build(int p,int l,int r)//建树 build(1,1,n);  
{
    if (l==r)ans[p]=a[l];
    else {
        int m=(l+r)>>1;
        build(p<<1,l,m);
        build(p<<1|1,m+1,r);
        ans[p]=ans[p<<1]+ans[p<<1|1];
    }
}
void pushdown(int p,int l,int r)
{                               //l表示左子树元素结点个数,r表示右子树结点个数
    if (lazy[p])
    {
        lazy[p<<1]+=lazy[p];
        lazy[p<<1|1]+=lazy[p];
        ans[p<<1]+=lazy[p]*l;
        ans[p<<1|1]+=lazy[p]*r;
        lazy[p]=0;
    }
}
void add(int p,int l,int r,int L,int C)//点更新 add(1,1,n,L,C); 
{
    if (l==r){ans[p]+=C;return;}       //更新结点信息
    int m=(l+r)>>1;
    //pushdown(p,m-l+1,r-m); 若既有点更新又有区间更新,需要这句话
    if (L<=m) add(p<<1,l,m,L,C);
    else add(p<<1|1,m+1,r,L,C);
    ans[p]=ans[p<<1]+ans[p<<1|1];
}

void update(int p,int l,int r,int L,int R,int C)
{                               //区间修改 update(1,1,n,L,R,C); 
    if (L<=l&&r<=R)
    {
        ans[p]+=C*(r-l+1);
        lazy[p]+=C;
        return;
    }
    int m=(l+r)>>1;
    pushdown(p,m-l+1,r-m);
    if (L<=m) update(p<<1,l,m,L,R,C);
    if (R>m) update(p<<1|1,m+1,r,L,R,C);
    ans[p]=ans[p<<1]+ans[p<<1|1];
}
ll query(int p,int l,int r,int L,int R) //区间查询 query(1,1,n,L,R); 
{
    if (L<=l&&r<=R) return ans[p];
    int m=(l+r)>>1;
    pushdown(p,m-l+1,r-m);//若更新只有点更新,不需要这句
    ll sum=0;
    if (L<=m) sum+=query(p<<1,l,m,L,R);
    if (R>m) sum+=query(p<<1|1,m+1,r,L,R);
    return sum;
}
//单点更新实现区间更新,某些更新次数有限的题目可用
void update(int o,int l,int r,int x,int y)
{
	//if(a[o]==(r-l+1))return ;
    if(l==r) {
		a[o]=sqrt((double)a[o]);
		return;
	}
    int m=(l+r)/2;
    int ls=2*o,rs=ls+1;
    if(x<=m) update(ls,l,m,x,y);    //与单点更新不同之处
    if(y>m)update(rs,m+1,r,x,y);    //
    a[o]=a[ls]+a[rs];
}

洛谷模板题(区间加法和乘法)

双延迟标记

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
ll a[maxn<<2],t[maxn];
ll add[maxn<<2],mul[maxn<<2];
ll q;
void build(ll p,ll l,ll r)
{
    mul[p]=1;add[p]=0;
    if(l==r){a[p]=t[l]%q;return ;}
    ll m=(l+r)>>1;
    build(p<<1,l,m);
    build(p<<1|1,m+1,r);
    a[p]=(a[p<<1]+a[p<<1|1])%q;
}
void pushdown(int p,int l,int r)
{
    a[p<<1]=(a[p<<1]*mul[p]+add[p]*l)%q;
    a[p<<1|1]=(a[p<<1|1]*mul[p]+add[p]*r)%q;
    mul[p<<1]=(mul[p<<1]*mul[p])%q;
    mul[p<<1|1]=(mul[p<<1|1]*mul[p])%q;
    add[p<<1]=(add[p<<1]*mul[p]+add[p])%q;
    add[p<<1|1]=(add[p<<1|1]*mul[p]+add[p])%q;
    mul[p]=1;add[p]=0;
}

void update(ll p,ll l,ll r,ll L,ll R,ll c,ll k)
{
    if(L<=l&&R>=r){
        if(k==1){
            a[p]=(a[p]*c)%q;
            mul[p]=(mul[p]*c)%q;
            add[p]=(add[p]*c)%q;
        }
        else if(k==2){
            a[p]=(a[p]+c*(r-l+1))%q;
            add[p]=(add[p]+c)%q;
        }
        return ;
    }
    ll m=(l+r)>>1;
    pushdown(p,m-l+1,r-m);
    if(L<=m)update(p<<1,l,m,L,R,c,k);
    if(R>m)update(p<<1|1,m+1,r,L,R,c,k);
    a[p]=(a[p<<1]+a[p<<1|1])%q;
}
ll query(ll p,ll l,ll r,ll L,ll R)
{
    if(L<=l&&R>=r)return a[p];
    ll m=(l+r)>>1;
    pushdown(p,m-l+1,r-m);
    ll sum=0;
    if(L<=m)sum+=query(p<<1,l,m,L,R);
    sum%=q;
    if(R>m)sum+=query(p<<1|1,m+1,r,L,R);
    sum%=q;
    return sum;
}
int main()
{
    ll n,m;
    scanf("%lld%lld%lld",&n,&m,&q);
    for(ll i=1;i<=n;i++)scanf("%lld",&t[i]);
    build(1,1,n);
    ll a,l,r,c;
    while(m--)
    {
        scanf("%lld%lld%lld",&a,&l,&r);
        if(a==1){
            scanf("%lld",&c);
            update(1,1,n,l,r,c,a);
        }
        else if(a==2){
            scanf("%lld",&c);
            update(1,1,n,l,r,c,a);
        }
        else if(a==3){
            ll ans=query(1,1,n,l,r);
            printf("%lld\n",ans);
        }
    }
    return 0;
}

树状数组

这位兄弟讲得超级好

模板

inline int lowbit(int x){return x&(-x);}
void update(int x,int d){
    while(x<=m){
        a[x]+=d;
        x+=lowbit(x);
    }
}
ll sum(int x){
    ll s=0;
    while(x>0){
        s+=a[x];
        x-=lowbit(x);
    }
    return s;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值