第一次用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; }