线段树模板

区间加,区间查询,改编版zkw,(原理基于zkw,把差分换成了pushDown),时间少,代码短,好写。

向上更新:

inline void pushUp(int x){
    tree[x]=tree[x<<1]+tree[x<<1|1];
}

建树

void build(){
    for(M=1;M<n+3;M<<=1);
    for(register int i=1;i<=n;++i)scanf("%d",&tree[i+M]);
    for(register int i=M;i<=(M<<1);++i)size[i]=1;
    for(register int i=M-1;i;--i)size[i]=size[i<<1]+size[i<<1|1],pushUp(i);
}

单节点添加

inline void addNode(int x,int v){
    adds[x]+=v;tree[x]+=size[x]*v;
}

从树根向下更新

void pushDown(int x){
    if(x^1)pushDown(x>>1);
    if(adds[x])addNode(x<<1,adds[x]),addNode(x<<1|1,adds[x]);
    adds[x]=0;
}

区间加

void add(int l,int r,LL v){
    pushDown((l+=M-1)>>1),pushDown((r+=M+1)>>1);
    for(;l^r^1;l>>=1,r>>=1){
        if(~l&1)addNode(l^1,v);if(r&1)addNode(r^1,v);
        pushUp(l>>1),pushUp(r>>1);
    }for(l>>=1;l;l>>=1)pushUp(l);
}

区间查询

LL query(int l,int r){LL ans=0;
    pushDown((l+=M-1)>>1),pushDown((r+=M+1)>>1);
    for(;l^r^1;l>>=1,r>>=1){
        if(~l&1)ans+=tree[l^1];if(r&1)ans+=tree[r^1];
    }return ans;
}

顺便附上模板代码,洛谷P3372:

#include<iostream>
#include<cstdio>
using namespace std;
#define LL long long
const int maxn = 1e5+5;
int n,m,M;
LL tree[maxn<<2],adds[maxn<<2],size[maxn<<2];
inline void pushUp(int x){
    tree[x]=tree[x<<1]+tree[x<<1|1];
}
void build(){
    for(M=1;M<n+3;M<<=1);
    for(register int i=1;i<=n;++i)scanf("%d",&tree[i+M]);
    for(register int i=M;i<=(M<<1);++i)size[i]=1;
    for(register int i=M-1;i;--i)size[i]=size[i<<1]+size[i<<1|1],pushUp(i);
}
inline void addNode(int x,int v){
    adds[x]+=v;tree[x]+=size[x]*v;
}
void pushDown(int x){
    if(x^1)pushDown(x>>1);
    if(adds[x])addNode(x<<1,adds[x]),addNode(x<<1|1,adds[x]);
    adds[x]=0;
}
void add(int l,int r,LL v){
    pushDown((l+=M-1)>>1),pushDown((r+=M+1)>>1);
    for(;l^r^1;l>>=1,r>>=1){
        if(~l&1)addNode(l^1,v);if(r&1)addNode(r^1,v);
        pushUp(l>>1),pushUp(r>>1);
    }for(l>>=1;l;l>>=1)pushUp(l);
}
LL query(int l,int r){LL ans=0;
    pushDown((l+=M-1)>>1),pushDown((r+=M+1)>>1);
    for(;l^r^1;l>>=1,r>>=1){
        if(~l&1)ans+=tree[l^1];if(r&1)ans+=tree[r^1];
    }return ans;
}
int main(){
    int m;scanf("%d%d",&n,&m);
    build();
    while(m--){
        int a,b,c,d;scanf("%d%d%d",&a,&b,&c);
        if(b>c)swap(b,c);
        if(a==1)scanf("%d",&d),add(b,c,d);
        else printf("%lld\n",query(b,c));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值