题意:
思路:
很明显的数据结构了,
s
p
l
a
y
splay
splay当然能写,但是
f
h
q
−
t
r
e
a
p
fhq-treap
fhq−treap更加简洁易懂。
考虑第一个操作,无非就是分裂出
[
1
,
p
o
s
−
1
]
[1,pos-1]
[1,pos−1]与
[
p
o
s
,
n
]
[pos,n]
[pos,n],让后再新建一个节点
n
o
w
now
now,将
[
1
,
p
o
s
−
1
]
,
n
o
w
,
[
p
o
s
,
n
]
[1,pos-1],now,[pos,n]
[1,pos−1],now,[pos,n]合并起来就好了。
第二个操作分裂出
[
l
,
r
]
[l,r]
[l,r]的区间,让后更新即可。
第三个操作分裂出
[
l
,
r
]
[l,r]
[l,r]的区间,输出
s
u
m
sum
sum即可。
需要注意的点:
(
1
)
(1)
(1)每次分裂后都别忘记
m
e
r
g
e
merge
merge。
(
2
)
(2)
(2)上传信息的时候,
s
u
m
sum
sum别忘记加上当前子树根的
v
a
l
val
val,道理跟
s
i
z
e
size
size一样。
(
3
)
(3)
(3)懒标记更新的时候别忘记更新
v
a
l
val
val。
这里采用了笛卡尔树建树 O ( n ) O(n) O(n)的方式以及直接建树 O ( n l o g n ) O(nlogn) O(nlogn)的方式。
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;
//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n,m,x,y,z,root,tot;
int stk[N];
struct Node {
int l,r;
int size,rank;
LL sum,lazy,val;
}tr[N<<2];
int newnode(int val) {
int u=++tot;
tr[u].val=tr[u].sum=val;
tr[u].rank=rand();
tr[u].size=1;
tr[u].l=tr[u].r=tr[u].lazy=0;
return u;
}
void pushup(int u) {
tr[u].sum=tr[tr[u].l].sum+tr[tr[u].r].sum+tr[u].val;
tr[u].size=tr[tr[u].l].size+tr[tr[u].r].size+1;
}
void pushdown(int u) {
if(tr[u].lazy!=0) {
LL lazy=tr[u].lazy; tr[u].lazy=0;
int ls=tr[u].l,rs=tr[u].r;
tr[ls].sum+=tr[ls].size*lazy; tr[ls].lazy+=lazy; tr[ls].val+=lazy;
tr[rs].sum+=tr[rs].size*lazy; tr[rs].lazy+=lazy; tr[rs].val+=lazy;
}
}
void split(int u,int k,int &x,int &y) {
if(!u) { x=y=0; return; }
pushdown(u);
if(k<=tr[tr[u].l].size) y=u,split(tr[u].l,k,x,tr[u].l);
else x=u,split(tr[u].r,k-tr[tr[u].l].size-1,tr[u].r,y);
pushup(u);
}
int merge(int u,int v) {
if(!u||!v) return u+v;
if(tr[u].rank<tr[v].rank) {
pushdown(u);
tr[u].r=merge(tr[u].r,v);
pushup(u);
return u;
}
else {
pushdown(v);
tr[v].l=merge(u,tr[v].l);
pushup(v);
return v;
}
}
void build() {
int cur=0,top=0;
for(int i=1;i<=n;i++) {
int val; scanf("%d",&val);
int now=newnode(val);
cur=top;
while(cur&&tr[stk[cur]].rank>tr[now].rank) pushup(stk[cur]),cur--;
if(cur) tr[stk[cur]].r=now,pushup(stk[cur]);
if(cur<top) tr[now].l=stk[cur+1],pushup(now);
stk[++cur]=i; top=cur;
}
while(top) pushup(stk[top--]);
root=stk[1];
}
void dfs(int u) {
if(tr[u].l) dfs(tr[u].l);
if(u) printf("%d ",tr[u].val);
if(tr[u].r) dfs(tr[u].r);
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
scanf("%d",&n);
build();
/*
for(int i=1;i<=n;i++) {
int val; scanf("%d",&val);
root=merge(root,newnode(val));
}
*/
int q; scanf("%d",&q);
while(q--) {
int op; scanf("%d",&op);
if(op==1) {
int pos; scanf("%d",&pos);
split(root,pos-1,x,y);
root=merge(merge(x,newnode(0)),y);
}
else if(op==2) {
int l,r,val; scanf("%d%d%d",&l,&r,&val);
split(root,r,x,y); split(x,l-1,x,z);
tr[z].sum+=1ll*tr[z].size*val;
tr[z].lazy+=val;
tr[z].val+=val;
root=merge(merge(x,z),y);
}
else {
int l,r; scanf("%d%d",&l,&r);
split(root,r,x,y); split(x,l-1,x,z);
printf("%lld\n",tr[z].sum);
root=merge(merge(x,z),y);
}
}
return 0;
}
/*
*/