题意:见下图
传说级别的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)); }
奉上读入优化版本,因为有的OJ卡这个题的常数(比如我们学校自己的oj)
同学帮着写的,效率十分可观,BZOJ3472ms就过了
CODE(读入优化):
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cctype> #define MAX 600010 #define INF 0x7f7f7f7f using namespace std; inline int getc() { static const int L = 1 << 15; static char buf[L], *S = buf, *T = buf; if (S == T) { T = (S = buf) + fread(buf, 1, L, stdin); if (S == T) return EOF; } return *S++; } inline int getint() { int c; while(!isdigit(c = getc()) && c != '-'); bool sign = c == '-'; int tmp = sign ? 0 : c - '0'; while(isdigit(c = getc())) tmp = (tmp << 1) + (tmp << 3) + c - '0'; return sign ? -tmp : tmp; } struct Twochar { char c0, c1; Twochar(char _c0 = 0, char _c1 = 0):c0(_c0),c1(_c1){} }; inline Twochar getch() { int c; while((c = getc()) != 'I' && c != 'D' && c != 'M' && c != 'R' && c != 'G'); int c2 = getc(); c2 = getc(); if(c == 'I'&&c2=='S')getc(),getc(),getc(); if(c == 'D'&&c2=='L')getc(),getc(),getc(); if(c=='M'&&c2=='K')getc(),getc(),getc(),getc(),getc(); if(c=='R'&&c2=='V')getc(),getc(),getc(),getc(); if(c=='G'&&c2=='T')getc(),getc(),getc(),getc(); if(c=='M'&&c2=='X')getc(),getc(),getc(),getc(); return Twochar(c, c2); } 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); int cnt,asks; int pos,num; int temp[MAX]; int main() { cnt = getint(); asks = getint(); Pretreatment(); for(int i = 1;i <= cnt; ++i) temp[i] = getint(); root = BuildTree(0,cnt + 1); root->father = nil; Twochar s; for(int i = 1;i <= asks; ++i) { s = getch(); if(s.c0 == 'I' && s.c1 == 'S') { pos=getint(),cnt=getint(),pos++; for(int i = 1;i <= cnt; ++i) temp[i]=getint(); 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(s.c0 == 'D' && s.c1 == 'L') { pos=getint(),cnt=getint(); 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(s.c0 == 'M' && s.c1 == 'K') { pos=getint(),cnt=getint(),num=getint(); SplaySeg(pos,pos + cnt - 1); root->son[1]->son[0]->Change(num); PushUp(root->son[1]),PushUp(root); } else if(s.c0 == 'R' && s.c1 == 'V') { pos=getint(),cnt=getint(); SplaySeg(pos,pos + cnt - 1); root->son[1]->son[0]->Reverse(); PushUp(root->son[1]),PushUp(root); } else if(s.c0 == 'G' && s.c1 == 'T') { pos=getint(),cnt=getint(); SplaySeg(pos,pos + cnt - 1); printf("%d\n",root->son[1]->son[0]->sum); } else if(s.c0 == 'M' && s.c1 == 'X') { 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)); }