BZOJ 1500 NOI2005 维修数列 题解
题目大意:要求维护一个序列,支持插入,删除,修改(将一段区间内的数全部设置为c),区间翻转,区间求和,区间最大和。
splay维护。其中区间最大和用一个mmax值来记录,需要用lmax和rmax来辅助(代表前缀最大和和后缀最大和)。
mmax有三种情况:区间全部在左子树中,区间全部在右子树中,区间跨越左右子树。
lmax有两种情况:区间全部在左子树中,区间跨越左右子树。这样更新一下即可。
(更新的时候有一些小细节,详见代码)
注意Reverse操作。mmax不变,lmax和rmax交换。注意这题因为有附加值,不能像SuperMemo那题一样翻转时只修改标记,下传的时候再真正修改。
注意操作结束之后要对父亲进行maintain维护。(不过在MakeSame和Reverse操作之后不maintain也可以,不知道为什么)
(不过maintain操作是O(1)的,多maintain几次没坏处...)
1 #include<cstdio> 2 #include<algorithm> 3 const int MAXN=1000000+10; 4 const int INF=~0U>>1; 5 int a[MAXN]; 6 struct Node{ 7 int s,v; 8 int lmax,rmax,mmax,sum; 9 bool rev,same; 10 Node* p,*ch[2]; 11 Node() {same=sum=s=v=rev=0;lmax=rmax=mmax=-INF;} 12 inline void maintain() 13 { 14 s=ch[0]->s+ch[1]->s+1; 15 sum=v+ch[0]->sum+ch[1]->sum; 16 lmax=std::max(ch[0]->lmax,ch[0]->sum+v+std::max(0,ch[1]->lmax)); 17 rmax=std::max(ch[1]->rmax,ch[1]->sum+v+std::max(0,ch[0]->rmax)); 18 mmax=std::max(std::max(ch[0]->mmax,ch[1]->mmax),std::max(0,ch[0]->rmax)+v+std::max(0,ch[1]->lmax)); 19 } 20 inline void setc(Node* t,bool d) 21 { 22 ch[d]=t; 23 t->p=this; 24 } 25 inline void MakeSame(int sv) 26 { 27 v=sv; 28 same=1; 29 sum=s*sv; 30 mmax=rmax=lmax=std::max(v,sum); 31 } 32 inline void revIt() 33 { 34 std::swap(ch[0],ch[1]); 35 std::swap(lmax,rmax); 36 rev^=1; 37 } 38 inline bool d() {return p->ch[1]==this;} 39 inline void pushdown(); 40 }Tnull,*null=&Tnull; 41 inline void Node::pushdown() 42 { 43 if(rev) 44 { 45 if(ch[0]!=null) ch[0]->revIt(); 46 if(ch[1]!=null) ch[1]->revIt(); 47 rev=0; 48 } 49 if(same) 50 { 51 if(ch[0]!=null) ch[0]->MakeSame(v); 52 if(ch[1]!=null) ch[1]->MakeSame(v); 53 same=0; 54 } 55 } 56 Node* root; 57 inline void rot(Node* t) 58 { 59 Node* p=t->p; 60 p->pushdown();t->pushdown(); 61 bool d=t->d(); 62 p->p->setc(t,p->d()); 63 p->setc(t->ch[d^1],d); 64 t->setc(p,d^1); 65 p->maintain(); 66 if(p==root) 67 root=t; 68 } 69 void splay(Node* t,Node* f=null) 70 { 71 while(t->p!=f) 72 { 73 if(t->p->p==f) rot(t); 74 else t->d()==t->p->d()?(rot(t->p),rot(t)):(rot(t),rot(t)); 75 } 76 t->maintain(); 77 } 78 Node* select(int k) 79 { 80 for(Node* t=root;;) 81 { 82 t->pushdown(); 83 int s=t->ch[0]->s; 84 if(k==s) return t; 85 if(k>s) k-=s+1,t=t->ch[1]; 86 else t=t->ch[0]; 87 } 88 } 89 inline Node*& get(int l,int r) //[l,r) 90 { 91 Node* L=select(l-1); 92 Node* R=select(r); 93 splay(L); 94 splay(R,L); 95 return R->ch[0]; 96 } 97 void DeleteTree(Node*& t) 98 { 99 if(t==null) return; 100 DeleteTree(t->ch[0]); 101 DeleteTree(t->ch[1]); 102 delete t; 103 t=null; 104 } 105 Node* build(int l,int r) //[l,r) 106 { 107 if(l>=r) return null; 108 int m=l+r>>1; 109 Node* t=new Node(); 110 Node* L=build(l,m),*R=build(m+1,r); 111 t->v=t->sum=t->lmax=t->rmax=t->mmax=a[m]; 112 t->setc(L,0); 113 t->setc(R,1); 114 t->maintain(); 115 return t; 116 } 117 void Insert(int pos,int tot) 118 { 119 if(!tot) return; 120 for(int i=0;i<tot;++i) scanf("%d",a+i); 121 Node* t=build(0,tot); 122 splay(select(pos)); 123 splay(select(pos+1),root); 124 root->ch[1]->setc(t,0); 125 root->ch[1]->maintain(); 126 root->maintain(); 127 } 128 inline void Delete(int pos,int tot) 129 { 130 if(!tot) return; 131 Node*& t=get(pos,pos+tot); 132 DeleteTree(t); 133 root->ch[1]->maintain(); 134 root->maintain(); 135 } 136 inline void MakeSame(int pos,int tot,int c) 137 { 138 if(!tot) return; 139 Node*& t=get(pos,pos+tot); 140 t->MakeSame(c); 141 t->p->maintain(); 142 t->p->p->maintain(); 143 } 144 inline void Reverse(int pos,int tot) 145 { 146 if(!tot || tot==1) return; 147 Node*& t=get(pos,pos+tot); 148 t->revIt(); 149 t->p->maintain(); 150 t->p->p->maintain(); 151 } 152 inline int GetSum(int pos,int tot) 153 { 154 if(!tot) return 0; 155 Node*& t=get(pos,pos+tot); 156 return t->sum; 157 } 158 inline int MaxSum() 159 { 160 Node*& t=get(1,root->s-1); 161 return t->mmax; 162 } 163 int n,m; 164 char s[20]; 165 int main() 166 { 167 //freopen("sequence.in","r",stdin); 168 //freopen("sequence.out","w",stdout); 169 scanf("%d%d",&n,&m); 170 for(int i=1;i<=n;++i) scanf("%d",a+i); 171 root=build(0,n+2); 172 root->p=null; 173 while(m--) 174 { 175 int pos,tot,c; 176 scanf("%s",s); 177 if(s[2]!='X') scanf("%d%d",&pos,&tot); 178 if(s[2]=='K') scanf("%d",&c); 179 switch(s[2]) 180 { 181 case 'T':printf("%d\n",GetSum(pos,tot)); 182 break; 183 case 'S':Insert(pos,tot); 184 break; 185 case 'V':Reverse(pos,tot); 186 break; 187 case 'L':Delete(pos,tot); 188 break; 189 case 'X':printf("%d\n",MaxSum()); 190 break; 191 case 'K':MakeSame(pos,tot,c); 192 break; 193 } 194 } 195 return 0; 196 }