第一次用splay做关于数列的题,比一般的splay写法更加麻烦,但是它是基于元素的,而线段树是基于整段区间的,所以在数据范围大而且分散的情况下线段树几乎不能做(Ps:可以考虑离散化),这个时候就可以使用splay来维护一个数列。
这道题不能用线段树做的原因不是因为数据范围,而是这道题涉及到了翻转操作,线段树不支持这种操作,所以用splay来维护。
对于每个节点维护val,Max和add表示当前节点的值,区间最大值和懒标记,在旋转的时候需要将标记一起传递,并且 需要注意的是这里的splay并不是二叉查找树,而是区间树,只能用来做一些与区间有关的操作。这道题是splay维护区间的模板题,比较简单,只是需要注意的是初值,一开始都为负无穷,还有在标记传递的时候一定要判断一下左右儿子是否存在,否则会出现统计错误(值增加多次)使答案变得很大。
代码:
#include<cstdio>
#include<cstring>
#define keyTree ch[ ch[root][1] ][0]
using namespace std;
const int maxn = 50000 + 10;
const int inf = 0x3f3f3f3f;
struct SplayTree
{
int ch[maxn][2],pre[maxn];
int val[maxn],add[maxn],Max[maxn];
bool reserve[maxn];
int sz[maxn];
int root,top;
int max(int a,int b)
{
return a > b ? a : b;
}
void swap(int &a,int &b)
{
int t = a;a = b;b = t;
}
void push_up(int x)
{
sz[x] = sz[ ch[x][0] ] + sz[ ch[x][1] ] + 1;
Max[x] = max(val[x],max(Max[ ch[x][0] ],Max[ ch[x][1] ]));
}
void push_down(int x)
{
if(add[x])
{
if(ch[x][0])
{
Max[ ch[x][0] ] += add[x];
val[ ch[x][0] ] += add[x];
add[ ch[x][0] ] += add[x];
}
if(ch[x][1])
{
Max[ ch[x][1] ] += add[x];
val[ ch[x][1] ] += add[x];
add[ ch[x][1] ] += add[x];
}
add[x] = 0;
}
if(reserve[x])
{
if(ch[x][0])reserve[ ch[x][0] ] = !reserve[ ch[x][0] ];
if(ch[x][1])reserve[ ch[x][1] ] = !reserve[ ch[x][1] ];
swap(ch[x][0],ch[x][1]);
reserve[x] = false;
}
}
void Rotate(int x,int f)
{
int y = pre[x];
push_down(y);
push_down(x);
ch[y][!f] = ch[x][f];
pre[ ch[x][f] ] = y;
pre[x] = pre[y];
if(pre[x])ch[ pre[y] ][ ch[pre[y]][1] == y ] = x;
ch[x][f] = y;
pre[y] = x;
push_up(y);
}
void Splay(int x,int goal)
{
push_down(x);
while(pre[x] != goal)
{
if(pre[pre[x]] == goal)Rotate(x,ch[pre[x]][0] == x);
else
{
int y = pre[x],z = pre[y];
int f = (ch[z][0] == y);
if(ch[y][f] == x)Rotate(x, !f),Rotate(x, f);
else Rotate(y, f),Rotate(x, f);
}
}
push_up(x);
if(goal == 0)root = x;
}
void RotateTo(int k,int goal)
{
int x = root;
push_down(x);
while(sz[ ch[x][0] ] != k)
{
if(k < sz[ ch[x][0] ])x = ch[x][0];
else
{
k -= (sz[ ch[x][0] ] + 1);
x = ch[x][1];
}
push_down(x);
}
Splay(x,goal);
}
void update()
{
int l,r,c;
scanf("%d%d%d",&l,&r,&c);
RotateTo(l-1,0);
RotateTo(r+1,root);
val[ keyTree ] += c;
Max[ keyTree ] += c;
add[ keyTree ] += c;
}
int query()
{
int l,r;
scanf("%d%d",&l,&r);
RotateTo(l-1 ,0);
RotateTo(r+1, root);
return Max[ keyTree ];
}
void turn()
{
int l,r;
scanf("%d%d",&l,&r);
RotateTo(l-1, 0);
RotateTo(r+1, root);
reserve[ keyTree ] = !reserve[ keyTree ];
}
void Newnode(int &x,int c)
{
x = ++top;
ch[x][0] = ch[x][1] = pre[x] = 0;
sz[x] = 1;
val[x] = Max[x] = c;
add[x] = 0;
}
void makeTree(int &x,int l,int r,int f)
{
if(l > r)return;
int m = (l + r) >> 1;
Newnode(x,0);
makeTree(ch[x][0],l,m - 1,x);
makeTree(ch[x][1],m + 1,r,x);
pre[x] = f;
push_up(x);
}
void init(int n)
{
memset(Max,~0x3f,sizeof(Max));
memset(val,~0x3f,sizeof(val));
ch[0][0] = ch[0][1] = pre[0] = sz[0] = 0;
add[0] = 0;
root = top = 0;
Newnode(root, -1);
Newnode(ch[root][1], -1);
pre[2] = root;
sz[root] = 2;
makeTree(keyTree,1,n,ch[root][1]);
push_up(ch[root][1]);
push_up(root);
}
}Spt;
int n,m;
void init()
{
freopen("bzoj1251.in","r",stdin);
freopen("bzoj1251.out","w",stdout);
}
void readdata()
{
scanf("%d%d",&n,&m);
Spt.init(n);
for(int i = 1;i <= m;i++)
{
int op;
scanf("%d",&op);
if(op == 1)Spt.update();
if(op == 2)Spt.turn();
if(op == 3)printf("%d\n",Spt.query());
}
}
int main()
{
init();
readdata();
return 0;
}