2018.08.04 spoj TTM to the moon(主席树)

spoj传送门
vjudge传送门
主席树板子题。
支持历史版本的区间和,区间和,区间修改和时光倒流。
其中新奇一点的也只有区间修改了,这个东西直接标记永久化就行了。
如果想下传标记的话也行,需要在pushdown的时候新建一波节点。
代码:

#include<cstdio>
#include<cctype>
#define ll long long
#define N 100005
using namespace std;
inline ll read(){
    ll ans=0,w=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans*w;
}
inline void write(ll x){
    if(x<0)x=-x,putchar('-');
    if(x>9)write(x/10);
    putchar((x%10)^48);
}
inline ll max(ll a,ll b){return a>b?a:b;}
inline ll min(ll a,ll b){return a<b?a:b; }
int n,m,tot=0,rt[N*50],siz=0;
struct Node{int l,r;ll sum,add;}T[N*50];
inline void pushup(int p){T[p].sum=T[T[p].l].sum+T[T[p].r].sum;}
inline void build(int&p,int l,int r){
    p=++tot;
    if(l==r){T[p].sum=read();return;}
    int mid=l+r>>1;
    build(T[p].l,l,mid),build(T[p].r,mid+1,r),pushup(p);
}
inline void update(int&p,int las,int ql,int qr,int l,int r,ll v){
    T[p=++tot]=T[las];
    if(ql<=l&&r<=qr){T[p].add+=v;return;}
    T[p].sum+=v*(min(qr,r)-max(ql,l)+1);
    int mid=l+r>>1;
    if(qr<=mid)update(T[p].l,T[las].l,ql,qr,l,mid,v);
    else if(ql>mid)update(T[p].r,T[las].r,ql,qr,mid+1,r,v);
    else update(T[p].l,T[las].l,ql,mid,l,mid,v),update(T[p].r,T[las].r,mid+1,qr,mid+1,r,v);
}
inline ll query(int p,int ql,int qr,int l,int r){
    ll ret=T[p].add*(min(qr,r)-max(ql,l)+1);
    if(ql<=l&&r<=qr)return T[p].sum+ret;
    int mid=l+r>>1;
    if(qr<=mid)return ret+query(T[p].l,ql,qr,l,mid);
    if(ql>mid)return ret+query(T[p].r,ql,qr,mid+1,r);
    return ret+query(T[p].l,ql,mid,l,mid)+query(T[p].r,mid+1,qr,mid+1,r);
}
int main(){
    n=read(),m=read();
    build(rt[0],1,n);
    while(m--){
        char op[2];
        scanf("%s",op);
        if(op[0]=='C'){int l=read(),r=read();ll v=read();++siz,update(rt[siz],rt[siz-1],l,r,1,n,v);}
        if(op[0]=='Q'){int l=read(),r=read();printf("%lld\n",query(rt[siz],l,r,1,n));}
        if(op[0]=='H'){int l=read(),r=read(),p=read();printf("%lld\n",query(rt[p],l,r,1,n));}
        if(op[0]=='B')siz=read(),tot=rt[siz+1]-1;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值