标签:splay tree 平衡树 noi2005 数据结构 维修数列
题意:见下图
传说级别的NOI数据结构神题,像我这种弱渣花了一下午的时间才A掉,最后发现竟然是边界值的问题没处理好。。
这个题对Splay的所有操作基本是全了。
插入:新建一颗Splay Tree,然后把对应节点Splay到根的右儿子上,再把新建的树连上。
删除:把要删除的区间Splay到根的右儿子的左儿子上,递归free掉。(这里可以用数组优化,可以避免递归free节省时间)
修改,翻转:打标记,在需要的时候下传标记,和线段树差不多,翻转标记下传时,要将左右儿子的左右儿子分别交换。
求和:维护一个sum域。
求最大子列和:与线段树类似。维护一个区间从左边开始连续最大值,从右边开始连续最大值,整体的连续最大值。更新的时候注意下细节。不会的可以先去写vijos的小白逛公园,线段树的最大子列和,要比这个简单一些。详情见代码。
CODE(BZOJ5988ms):
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 600010 #define INF 0x7f7f7f7f using namespace std; const char INSERT[] = "INSERT"; const char DELETE[] = "DELETE"; const char REVERSE[] = "REVERSE"; const char GET_SUM[] = "GET-SUM"; const char MAX_SUM[] = "MAX-SUM"; const char MAKE_SAME[] = "MAKE-SAME"; struct Complex{ int val,size; bool change,reverse; int change_into; int sum; int l,r,all; Complex *son[2],*father; bool Check() { return father->son[1] == this; } void Combine(Complex *a,bool dir) { son[dir] = a; a->father = this; } void Reverse() { reverse ^= 1; swap(son[0],son[1]); swap(l,r); } void Change(int x) { val = x; sum = x * size; l = r = all = max(sum,val); change = true; change_into = x; } }none,*nil = &none,*root = nil; void Pretreatment(); inline Complex *NewComplex(int x); inline void Rotate(Complex *a,bool dir); inline void Splay(Complex *a,Complex *aim); Complex *BuildTree(int l,int r); inline void SplaySeg(int st,int ed); inline void PushUp(Complex *a); inline void PushDown(Complex *a); void Delete(Complex *a); Complex *FindK(Complex *a,int k); void Print(Complex *a) { if(a == nil) return ; PushDown(a); PushUp(a); Print(a->son[0]); printf("%d ",a->val); Print(a->son[1]); } int cnt,asks; int pos,num; int temp[MAX]; char s[20]; int main() { cin >> cnt >> asks; Pretreatment(); for(int i = 1;i <= cnt; ++i) scanf("%d",&temp[i]); root = BuildTree(0,cnt + 1); root->father = nil; for(int i = 1;i <= asks; ++i) { scanf("%s",s); if(!strcmp(s,INSERT)) { scanf("%d%d",&pos,&cnt),pos++; for(int i = 1;i <= cnt; ++i) scanf("%d",&temp[i]); Splay(FindK(root,pos),nil); Splay(FindK(root,pos + 1),root); root->son[1]->Combine(BuildTree(1,cnt),false); PushUp(root->son[1]),PushUp(root); } else if(!strcmp(s,DELETE)) { scanf("%d%d",&pos,&cnt); SplaySeg(pos,pos + cnt - 1); Delete(root->son[1]->son[0]); root->son[1]->son[0] = nil; PushUp(root->son[1]),PushUp(root); } else if(!strcmp(s,MAKE_SAME)) { scanf("%d%d%d",&pos,&cnt,&num); SplaySeg(pos,pos + cnt - 1); root->son[1]->son[0]->Change(num); PushUp(root->son[1]),PushUp(root); } else if(!strcmp(s,REVERSE)) { scanf("%d%d",&pos,&cnt); SplaySeg(pos,pos + cnt - 1); root->son[1]->son[0]->Reverse(); PushUp(root->son[1]),PushUp(root); } else if(!strcmp(s,GET_SUM)) { scanf("%d%d",&pos,&cnt); SplaySeg(pos,pos + cnt - 1); printf("%d\n",root->son[1]->son[0]->sum); } else if(!strcmp(s,MAX_SUM)) { int temp = root->size; Splay(FindK(root,1),nil); Splay(FindK(root,temp),root); printf("%d\n",root->son[1]->son[0]->all); } } return 0; } void Pretreatment() { nil->son[0] = nil->son[1] = nil; nil->father = nil; nil->size = 0; nil->all = -INF; temp[0] = temp[cnt + 1] = -INF; } inline Complex *NewComplex(int x) { Complex *re = new Complex(); re->son[0] = re->son[1] = nil; re->size = 1; re->sum = re->l = re->r = re->all = re->val = x; re->change = re->reverse = false; return re; } inline void Rotate(Complex *a,bool dir) { Complex *f = a->father; PushDown(f),PushDown(a); f->son[!dir] = a->son[dir]; f->son[!dir]->father = f; a->son[dir] = f; a->father = f->father; f->father->son[f->Check()] = a; f->father = a; PushUp(f); if(root == f) root = a; } inline void Splay(Complex *a,Complex *aim) { while(a->father != aim) { if(a->father->father == aim) Rotate(a,!a->Check()); else if(!a->father->Check()) { if(!a->Check()) { Rotate(a->father,true); Rotate(a,true); } else { Rotate(a,false); Rotate(a,true); } } else { if(a->Check()) { Rotate(a->father,false); Rotate(a,false); } else { Rotate(a,true); Rotate(a,false); } } PushUp(a); } } Complex *BuildTree(int l,int r) { if(l > r) return nil; int mid = (l + r) >> 1; Complex *now = NewComplex(temp[mid]); now->Combine(BuildTree(l,mid - 1),false); now->Combine(BuildTree(mid + 1,r),true); if(l != r) PushUp(now); return now; } void Delete(Complex *a) { if(a == nil) return ; Delete(a->son[0]),Delete(a->son[1]); free(a); } inline void SplaySeg(int st,int ed) { st += 1,ed += 1; Splay(FindK(root,st - 1),nil); Splay(FindK(root,ed + 1),root); } Complex *FindK(Complex *a,int k) { PushDown(a); if(k <= a->son[0]->size) return FindK(a->son[0],k); k -= a->son[0]->size; if(k == 1) return a; --k; return FindK(a->son[1],k); } inline void PushDown(Complex *a) { if(a == nil) return ; if(a->change) { if(a->son[0] != nil) a->son[0]->Change(a->change_into); if(a->son[1] != nil) a->son[1]->Change(a->change_into); a->change = false; } if(a->reverse) { if(a->son[0] != nil) a->son[0]->Reverse(); if(a->son[1] != nil) a->son[1]->Reverse(); a->reverse = false; } } inline void PushUp(Complex *a) { if(a == nil) return ; a->size = a->son[0]->size + a->son[1]->size + 1; a->sum = a->son[0]->sum + a->son[1]->sum + a->val; a->l = max(a->son[0]->l,a->son[0]->sum + a->val + max(0,a->son[1]->l)); a->r = max(a->son[1]->r,a->son[1]->sum + a->val + max(0,a->son[0]->r)); a->all = max(max(a->son[0]->all,a->son[1]->all),a->val+max(0,a->son[0]->r)+max(0,a->son[1]->l)); }
标签:splay tree 平衡树 noi2005 数据结构 维修数列
原文地址:http://blog.csdn.net/jiangyuze831/article/details/39098481