题意:
对于一个长度为n的序列,要求支持三种操作:
[l,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);
}