LOJ#6109. 「2017 山东二轮集训 Day4」增添(可持久化Treap)

传送门

题意:
对于一个长度为n的序列,要求支持三种操作:
[l,r] 增加 x
[l,l+x] 替换 [r,r+x]
[l,r] 求和

题解:
看到第二个操作,想到可持久化这个序列,可以用无旋 Treap 来可持久化。

可持久化平衡树支持各种操作,包括区间反转,下传等,只需要 pushdown 时新建子节点即可。

还有可持久化 Treap 的空间消耗非常大,如果不加入引用计数等操作最终空间会接近一个 G <script type="math/tex" id="MathJax-Element-45">G</script>,所以还是慎用这个数据结构吧。

贴一份版:

#include <bits/stdc++.h>
using namespace std;
typedef unsigned int uint;
typedef long long ll;
const int R_LEN=(1<<18)|1;
char ibuf[R_LEN],*sb,*tb;
inline char getc(){
    (sb==tb)&&(tb=(sb=ibuf)+fread(ibuf,1,R_LEN,stdin));
    return (sb==tb)?-1:*sb++;
}
inline int rd(){
    char ch=getc(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getc();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getc();}
    return i*f;
}
char obuf[R_LEN],*ob=obuf;
inline void print(char c){
    (ob==obuf+R_LEN)&&(fwrite(obuf,1,R_LEN,stdout),ob=obuf);
    *ob++=c;
}
inline void W(ll x){
    static int buf[50];
    if(!x){print('0');return;}
    if(x<0){print('-');x=-x;}
    while(x){buf[++buf[0]]=x%10;x/=10;}
    while(buf[0]){print(buf[buf[0]--]+'0');}
}
inline uint unit(int mod=0){
    static uint state0=19491001;
    state0^=(state0<<13);
    state0^=(state0>>17);
    state0^=(state0<<5);
    return mod?(state0%mod):state0;
}
const int N=2e5+50;
int n,m;
struct node{
    node *lc,*rc;
    int tag,val,sze;
    ll sum;
    uint pri;
    inline void upt(){
        sum=lc->sum+rc->sum+val;
        sze=lc->sze+rc->sze+1;
    }
    inline node* add(int x);
    inline node* pushdown();
    inline node* cpy();
}Pool[N*120],*pool=Pool,*null=Pool,*rt=null;
typedef pair<node*,node*> pii;
inline node* node::add(int x){
    ++pool; pool->lc=lc; pool->rc=rc;
    pool->sum=sum+(ll)sze*x; pool->val=val+x;
    pool->tag=tag+x; pool->sze=sze;
    return pool;
}
inline node* node::cpy(){
    ++pool; pool->lc=lc; pool->rc=rc;
    pool->sum=sum; pool->val=val;
    pool->tag=tag; pool->sze=sze;
    return pool;
}
inline node* node::pushdown(){
    if(!tag) return this->cpy();
    node *b=++pool; b=this->cpy();
    b->lc=(lc!=null)?lc->add(tag):null;
    b->rc=(rc!=null)?rc->add(tag):null;
    b->tag=0; return b;
}
inline void build(){
    static node* stk[N]; int tp=0;
    rt=&Pool[1]; stk[tp=1]=&Pool[1];
    for(int i=2;i<=n;i++){
        node *now=&Pool[i]; node *lst=null;
        while(tp&&now->pri>stk[tp]->pri) lst=stk[tp],stk[tp--]->upt();
        tp?(stk[tp]->rc=now):(rt=now);
        now->lc=lst; stk[++tp]=now;
    } while(tp) stk[tp--]->upt();
}
inline pii split(node *x,int sze){
    if(x==null) return make_pair(null,null);
    node *b=x->pushdown(); 
    if(b->lc->sze>=sze){
        pii tr1=split(b->lc,sze);
        b->lc=tr1.second; b->upt();
        return make_pair(tr1.first,b);
    }else{
        pii tr1=split(b->rc,sze-b->lc->sze-1);
        b->rc=tr1.first; b->upt();
        return make_pair(b,tr1.second);
    }
}
inline bool cmp(node *x,node *y){
    int sze=unit(x->sze+y->sze)+1;
    return sze<=x->sze;
}
inline node* merge(node *x,node *y){
    if(x==null&&y==null) return 0;
    if(x==null) return y->cpy();
    if(y==null) return x->cpy();
    if(cmp(x,y)){
        node *b=x->pushdown();
        b->rc=merge(b->rc,y);
        b->upt(); return b;
    }else{
        node *b=y->pushdown();
        b->lc=merge(x,b->lc);
        b->upt(); return b;
    }
}
int main(){
    n=rd(),m=rd();
    for(int i=1;i<=n;i++){
        ++pool; pool->val=rd();
        pool->lc=(pool->rc=null);
        pool->pri=unit(); 
    } build();
    for(int i=1;i<=m;i++){
        int op=rd(),l=rd(),r=rd();
        if(op==1){
            pii tr1=split(rt,l-1);
            pii tr2=split(tr1.second,r-l+1);
            tr2.first=tr2.first->add(rd());
            rt=merge(tr1.first,merge(tr2.first,tr2.second));
        }else if(op==2){
            int x=rd();
            pii tr1=split(rt,l-1);
            pii tr2=split(tr1.second,++x);
            pii tr3=split(rt,r-1);
            pii tr4=split(tr3.second,x);
            rt=merge(tr3.first,merge(tr2.first,tr4.second));
        }else{
            pii tr1=split(rt,l-1);
            pii tr2=split(tr1.second,r-l+1);
            W(tr2.first->sum); print('\n');
            rt=merge(tr1.first,merge(tr2.first,tr2.second));
        }
    }
    fwrite(obuf,1,ob-obuf,stdout);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值