因为感觉
S
p
l
a
y
Splay
Splay比较难学。所以尝试去学了一下功能也同样强大的无旋
T
r
e
a
p
Treap
Treap,但是并没有理解很透彻。
无旋
T
r
e
a
p
Treap
Treap主要只有两个操作:
1.
s
p
l
i
t
:
1.split:
1.split: 把当前的树分割为两个平衡树。假设当前要取出前一个树的大小为
k
k
k,比较左子树的大小和
k
k
k,假如
k
≤
s
z
[
l
s
[
r
t
]
]
k\leq sz[ls[rt]]
k≤sz[ls[rt]],那么当前根一定是右子树的根,然后递归左儿子。左儿子的第一个根是左边的根,第二个根是右子树根的左儿子。对于另外一种情形,类似的讨论。
2.
m
e
r
g
e
:
2.merge:
2.merge:合并两个平衡树。而且总是把权值小的那个根作为最终的根。这样合并的方式就一定是唯一的。假设有两个树
r
t
1
,
r
t
2
rt1,rt2
rt1,rt2,并且第一个根的权值小于第二个根。就递归把第一个根的右儿子和第二个根合并。
这个题的题意是开始给出一个全部为0的序列。
然后支持三种操作:区间加,区间最值和区间翻转。
这里用
T
r
e
a
p
Treap
Treap方便实现区间翻转,直接分裂两次取出
[
l
,
r
]
[l,r]
[l,r]这一段,然后在根上打上标记,同时交换左右两个儿子。对于区间加也用同样的标记的方法。区间最值在
p
u
s
h
u
p
pushup
pushup的过程中更新。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=5e4+7;
int n,m,x,y,z,rt;
int r[N],sz[N],ls[N],rs[N];
ll v[N],mx[N];
int tag1[N],tag2[N];
int tot=0;
int build(int rt) {
r[++tot]=rand();
sz[tot]=1;
return tot;
}
void add(int rt,int val) {
mx[rt]+=val;
tag2[rt]+=val;
v[rt]+=val;
}
void rotate(int rt) {
swap(ls[rt],rs[rt]);
tag1[rt]^=1;
}
void pushup(int rt) {
sz[rt]=sz[ls[rt]]+sz[rs[rt]]+1;
mx[rt]=v[rt];
if(ls[rt]) mx[rt]=max(mx[rt],mx[ls[rt]]);
if(rs[rt]) mx[rt]=max(mx[rt],mx[rs[rt]]);
}
void pushdown(int rt) {
if(tag1[rt]) {
if(ls[rt]) rotate(ls[rt]);
if(rs[rt]) rotate(rs[rt]);
tag1[rt]=0;
}
if(tag2[rt]) {
if(ls[rt]) add(ls[rt],tag2[rt]);
if(rs[rt]) add(rs[rt],tag2[rt]);
tag2[rt]=0;
}
}
void split(int rt,int k,int &x,int &y) {
if(!rt) { x=y=0;return; }
pushdown(rt);
if(sz[ls[rt]]<k) {
x=rt;
split(rs[rt],k-sz[ls[rt]]-1,rs[x],y);
}
else {
y=rt;
split(ls[rt],k,x,ls[y]);
}
pushup(rt);
}
int merge(int x,int y) {
if(!x||!y) return x+y;
pushdown(x);
pushdown(y);
if(r[x]<r[y]) {
rs[x]=merge(rs[x],y);
pushup(x);
return x;
}
else {
ls[y]=merge(x,ls[y]);
pushup(y);
return y;
}
}
int main() {
srand(20190828);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
rt=merge(rt,build(i));
while(m--) {
int opt,l,r;
scanf("%d%d%d",&opt,&l,&r);
if(opt==1) {
ll c;
scanf("%lld",&c);
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
add(y,c);
rt=merge(merge(x,y),z);
}
else if(opt==2) {
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
rotate(y);
rt=merge(merge(x,y),z);
}
else {
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
printf("%lld\n",mx[y]);
rt=merge(merge(x,y),z);
}
}
return 0;
}