题目描述 Description
给定一个长度为N的序列,每个序列的元素是一个整数。要支持以下三种操作:
1.将[L,R]这个区间内的所有数加上V
2.将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1
3.求[L,R]这个区间中的最大值
最开始所有元素都是0。
输入描述 Input Description
第一行两个整数N,M。M为操作个数。 以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。
输出描述 Output Description
对于每个第3种操作,给出正确的回答。
样例输入 Sample Input
4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
样例输出 Sample Output
2
数据范围及提示 Data Size & Hint
N<=50000,M<=100000。
分析:
BZOJ 3223 文艺平衡树升级版
与原题不同的是,这里多了区间加法,区间求最大值
根据原题的思想,我们直接将区间加打上一个lazy标记延迟更新,放在pushdown一起下传即可
而区间求最大值在更新size值时一起维护一下就好了(放在update里面)
记得打lazy标记时可以直接将最大值加上新增lazy标记的大小
每次进行区间操作时,我们只需要将l-1号节点交换到root处,将r+1号节点交换到ch[root][1]处即可保证我们要操作的序列为r+1号节点的左子树,所以对子树进行操作即可(有没有想到线段树?)
实现: 由于我们需要操作l-1和r+1,所以需要增加两个哨兵节点,将编号推至1~n+2,操作l和r+2即可。并且额外增加一个lazy数组表示延迟更新的值,增加一个mx数组表示以每个节点为根节点的子树最大值是多少。这里发现,像线段树一样,操作到哪个节点就将标记全部下传,将mx在update里面更新,lazy在pushdown里面更新。
注意,每次将区间加上x时,mx只需要直接加上x即可,不用重新更新
#include
using namespace std;
#define inf 2100000000
#define maxn 50010
int ch[maxn][2],data[maxn],size[maxn],f[maxn],tag[maxn],lazy[maxn],key[maxn],mx[maxn];
int sz,root,n,m;
int read() {
int ans=0,flag=1;
char ch=getchar();
while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();
return ans*flag;
}
bool get(int x) {return ch[f[x]][1]==x;} //return if his father`s right kid is him
void update(int x) {
int l=ch[x][0],r=ch[x][1];
size[x]=1+size[l]+size[r];
mx[x]=key[x];
if(l) mx[x]=max(mx[x],mx[l]);
if(r) mx[x]=max(mx[x],mx[r]);
return ;
}
void pushdown(int x) {
int &l=ch[x][0],&r=ch[x][1];
if(lazy[x]) {
if(l) lazy[l]+=lazy[x],mx[l]+=lazy[x],key[l]+=lazy[x];
if(r) lazy[r]+=lazy[x],mx[r]+=lazy[x],key[r]+=lazy[x];
lazy[x]=0;
}
if(tag[x]) {
tag[l]^=1;
tag[r]^=1;
swap(l,r);
tag[x]=0;
}
return ;
}
void rotate(int x) {
int old=f[x],oldf=f[old],whichx=get(x);
pushdown(old);
pushdown(x);
ch[old][whichx]=ch[x][whichx^1],f[ch[old][whichx]]=old;
ch[x][whichx^1]=old,f[old]=x;
f[x]=oldf;
if(oldf)
ch[oldf][ch[oldf][1]==old]=x;
update(old);
update(x);
return ;
}
void splay(int x,int tar) { //rotate x to tar
for(int fa;(fa=f[x])!=tar;rotate(x))
if(f[fa]!=tar)
rotate(get(x)==get(fa)?fa:x);
if(!tar)
root=x;
return ;
}
int findx(int x) { //by search the ranking return the treenumber
int now=root;
while(1) {
pushdown(now);
if(ch[now][0] && x<=size[ch[now][0]])
now=ch[now][0];
else {
int tmp=(ch[now][0]?size[ch[now][0]]:0)+1;
if(x<=tmp) return now;
x-=tmp;
now=ch[now][1];
}
}
}
int build(int l,int r,int fa) {
if(l>r) return 0;
int mid=(l+r)>>1;
int now=++sz;
mx[now]=key[now]=data[mid];
f[now]=fa;
tag[now]=0;
ch[now][0]=build(l,mid-1,now);
ch[now][1]=build(mid+1,r,now);
update(now);
return now;
}
int main() {
n=read(),m=read();
data[1]=-inf;
root=build(1,n+2,0);
for(int i=1;i<=m;i++) {
int cpt=read();
int l=read(),r=read();
l=findx(l);
r=findx(r+2);
switch(cpt) {
case 1:{
int v=read();
splay(l,0);
splay(r,l);
lazy[ch[ch[root][1]][0]]+=v;
key[ch[ch[root][1]][0]]+=v;
mx[ch[ch[root][1]][0]]+=v;
break;
}
case 2:{
splay(l,0);
splay(r,l);
tag[ch[ch[root][1]][0]]^=1;
break;
}
case 3:{
splay(l,0);
splay(r,l);
printf("%d\n",mx[ch[ch[root][1]][0]]);
break;
}
}
}
return 0;
}