poj3468 zkw线段树

这里使用了zkw线段树;
使标记永久化,并维护sum数组:仅考虑子树的区间和;
这样一个节点对答案的贡献就是子树和加上上方祖先的标记和;
代码中L,R数组均可省去(但由于笔者太懒。。。。。。)
这样就给出了一个与论文中不太一样的sb方法,但各种复杂度还是一样的;

#include<cstdio>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define rep2(i,k,n) for(int i=k;i>=n;i--)
using namespace std;
typedef long long ll;
void sc(ll& x){ll f=1;x=0;
    char c=getchar();while(c>'9' || c<'0'){if(c=='-')f=-f;c=getchar();}
    for(;c>='0' && c<='9';c=getchar())x=x*10+c-'0';
    x*=f;
}
void sc(int& x){int f=1;x=0;
    char c=getchar();while(c>'9' || c<'0'){if(c=='-')f=-f;c=getchar();}
    for(;c>='0' && c<='9';c=getchar())x=x*10+c-'0';
    x*=f;
}
typedef long long ll;
const int N=2e5+7;
ll v[N],sum[N<<1],dt[N<<1],L[N<<1],R[N<<1];
int M,n,m;
void build(){
    for(M=1;M<=n;M<<=1);
    rep(i,1,n)sum[M+i]=v[i];
    rep(i,1,M)L[M+i]=R[M+i]=i;
    rep2(i,M-1,1)sum[i]=sum[i<<1]+sum[i<<1|1],L[i]=L[i<<1],R[i]=R[i<<1|1];
}
inline void up(int x){if(x)sum[x]=sum[x<<1]+sum[x<<1|1]+(R[x]-L[x]+1)*dt[x];}
void Add(int s,int t,ll a){
    if(s>t)return;
    for(s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1){
        if(~s&1)dt[s^1]+=a,sum[s^1]+=(R[s^1]-L[s^1]+1)*a;
        if(t&1)dt[t^1]+=a,sum[t^1]+=(R[t^1]-L[t^1]+1)*a;
        up(s>>1),up(t>>1);
    }for(;s;s>>=1)up(s);
}
ll query(int s,int t){int l=s,r=t;
if(s>t)return 0;
    ll res=0;
    for(s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1){
        if(~s&1)res+=sum[s^1];
        if(t&1)res+=sum[t^1];
        if(l<=R[s>>1])res+=(R[s>>1]-l+1)*dt[s>>1];
        if(r>=L[t>>1])res+=(r-L[t>>1]+1)*dt[t>>1];
    }
    for(s>>=1;s;s>>=1)res+=(r-l+1)*dt[s];
    return res;
}int main(){
    sc(n),sc(m);
    rep(i,1,n)sc(v[i]);
    build();
    char s[20];int l,r;ll a;
    rep(i,1,m){
        scanf("%s",s);
        if(s[0]=='C'){sc(l),sc(r),sc(a);Add(l,r,a);}
        else {sc(l),sc(r);printf("%I64d\n",query(l,r));
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值