[BZOJ 1500]维修数列 [Splay Tree从进阶到住院]
历尽艰辛终于A掉了这题QwQ
贴COGS评论区几句话=.=
策爷:“splay/块状链表的自虐题。”。深刻理解到如果没有M倾向就不要去写这题了。。
-Chenyao2333
记得byvoid的博客上说这个题他当时写了整整一天,
我大约写了8个小时?
这种长代码程序结构一定要简单简单再简单,否则就是无限的调试了-QhelDIV
这道题太恶心辣
一定要处理好哨兵节点和null节点的数据,update时要注意!
【没有用哨兵节点的请随意-wumingshi
这题确实恶心还特喵的是个板子...
用Splay写的话思路非常明确,但是必须处理好两边的虚拟结点和空结点的标记值...(猝不及防的细节题...?)
算了算了先贴题面
1500: [NOI2005]维修数列
Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 14422 Solved: 4692Description
Input
输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。Output
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
Sample Input
9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
Sample Output
-1
10
1
10
HINT
首先简单梳理一下,题目要求支持的操作有:$Reverse/Set/Sum/MaxSum/Delete/Insert$.
其中需要下传标记的是$Set$和$Reverse$,分别使用两个$bool$型标记即可.其中$Set$操作标记的处理优先于$Reverse$因为$Set$操作会将整个区间设置为同一个值,翻转不翻转都一样233
我们注意到有$MaxSum$操作,这时我们需要分析一下.我们可以使用三个变量来存储有关信息:$lmax$存储以该区间左端开始向右的最大和,$rmax$存储以该区间右端为结尾向左的最大和,$maxSum$存储该区间内的最大连续和的值.这样就可以将$maxSum$分为三种情况:左子树的$maxSum$;右子树的$maxSum$;左子树$rmax$,右子树$lmax$和该节点的键值之和.分别代表完全位于左区间/完全位于右区间/跨越中间的最大连续和(此部分的分治策略可参见算法导论第三版中文版的4.1节).$lmax$和$rmax$则分别对应两种情况,以$lmax$为例,对应左子树的$lmax$值与左子树的$sum$值,该结点的键值和右子树的$lmax$值之和的最大值.$rmax$同理.
对于空结点要注意maxSum为-INF,其他值为0.(这个-INF坑死人了QwQ总是WA那一个点...)
更新时对于$sum<0$的情况要更新$lmax$与$rmax$为0,$maxSum$为键值.
代码非常锻炼码力...还有调试能力w...
对于调试可以参考一下我在下面代码中的 class SplayTree 里写的$Print$函数,按前序遍历顺序打印整棵树并按深度缩进...调试的时候帮了我不少忙来着w
袋马时间~~
1 /************************************** 2 Judge Result: Accepted 3 4 **************************************/ 5 #include <cstdio> 6 #include <vector> 7 #include <cstring> 8 #include <cstring> 9 #include <iostream> 10 #include <algorithm> 11 12 #define lch chd[0] 13 #define rch chd[1] 14 #define kch chd[k] 15 #define xch chd[k^1] 16 17 const int INF=0x2FFFFFFF; 18 19 class SplayTree{ 20 private: 21 struct Node{ 22 int k; 23 int sz; 24 int sm; 25 int lm; 26 int rm; 27 int ms; 28 bool set; 29 bool rev; 30 Node* prt; 31 Node* chd[2]; 32 Node(const int& key){ 33 this->k=key; 34 this->sm=key; 35 this->ms=key; 36 this->lm=key>=0?key:0; 37 this->rm=key>=0?key:0; 38 this->sz=1; 39 this->prt=NULL; 40 this->lch=NULL; 41 this->rch=NULL; 42 this->rev=false; 43 this->set=false; 44 } 45 ~Node(){ 46 if(this->lch!=NULL) 47 delete this->lch; 48 if(this->rch!=NULL) 49 delete this->rch; 50 } 51 inline void Maintain(){ 52 if(this!=NULL){ 53 this->sz=this->lch->size()+this->rch->size()+1; 54 this->sm=this->lch->sum()+this->rch->sum()+this->k; 55 this->lm=std::max(this->lch->lmax(),this->lch->sum()+this->k+this->rch->lmax()); 56 this->rm=std::max(this->rch->rmax(),this->rch->sum()+this->k+this->lch->rmax()); 57 this->ms=std::max(std::max(this->lch->maxSum(),this->rch->maxSum()),this->lch->rmax()+this->k+this->rch->lmax()); 58 } 59 } 60 inline void Swap(){ 61 if(this!=NULL){ 62 this->rev=!this->rev; 63 std::swap(this->lm,this->rm); 64 std::swap(this->lch,this->rch); 65 } 66 } 67 inline void Set(const int& key){ 68 if(this!=NULL){ 69 this->set=true; 70 this->k=key; 71 this->sm=key*this->sz; 72 this->lm=std::max(this->sm,0); 73 this->rm=std::max(this->sm,0); 74 this->ms=std::max(this->sm,this->k); 75 } 76 } 77 inline void PushDown(){ 78 if(this->set){ 79 this->set=this->rev=false; 80 this->lch->Set(this->k); 81 this->rch->Set(this->k); 82 } 83 if(this->rev){ 84 this->rev=false; 85 this->lch->Swap(); 86 this->rch->Swap(); 87 } 88 } 89 inline int sum(){ 90 return this==NULL?0:this->sm; 91 } 92 inline int maxSum(){ 93 return this==NULL?-INF:this->ms; 94 } 95 inline int key(){ 96 return this==NULL?0:this->k; 97 } 98 inline int lmax(){ 99 return this==NULL?0:this->lm; 100 } 101 inline int rmax(){ 102 return this==NULL?0:this->rm; 103 } 104 inline int size(){ 105 return this==NULL?0:this->sz; 106 } 107 }*root; 108 inline void Rotate(Node* root,int k){ 109 Node* tmp=root->xch; 110 root->PushDown(); 111 tmp->PushDown(); 112 tmp->prt=root->prt; 113 if(root->prt==NULL) 114 this->root=tmp; 115 else if(root->prt->lch==root) 116 root->prt->lch=tmp; 117 else 118 root->prt->rch=tmp; 119 root->xch=tmp->kch; 120 if(tmp->kch!=NULL) 121 tmp->kch->prt=root; 122 tmp->kch=root; 123 root->prt=tmp; 124 root->Maintain(); 125 tmp->Maintain(); 126 } 127 void Splay(Node* root,Node* prt=NULL){ 128 while(root->prt!=prt){ 129 int k=root->prt->lch==root; 130 if(root->prt->prt==prt){ 131 Rotate(root->prt,k); 132 } 133 else{ 134 int d=root->prt->prt->lch==root->prt; 135 Rotate(k==d?root->prt->prt:root->prt,k); 136 Rotate(root->prt,d); 137 } 138 } 139 } 140 Node* Build(const std::vector<int>& v,int l,int r){ 141 if(l>r) 142 return NULL; 143 int mid=(l+r)>>1; 144 Node* tmp=new Node(v[mid]); 145 tmp->lch=Build(v,l,mid-1); 146 tmp->rch=Build(v,mid+1,r); 147 if(tmp->lch!=NULL) 148 tmp->lch->prt=tmp; 149 if(tmp->rch!=NULL) 150 tmp->rch->prt=tmp; 151 tmp->Maintain(); 152 return tmp; 153 } 154 void PrintTree(Node* root,int deep){ 155 for(int i=0;i<deep;i++) 156 fputc(' ',stderr); 157 fprintf(stderr, "(root=0x%X,key=%d,sum=%d,size=%d,lmax=%d,rmax=%d,maxSum=%d)\n", root,root->key(),root->sum(),root->size(),root->lmax(),root->rmax(),root->maxSum()); 158 if(root==NULL) 159 return; 160 PrintTree(root->lch,deep+1); 161 PrintTree(root->rch,deep+1); 162 } 163 public: 164 SplayTree(){ 165 this->root=new Node(-INF); 166 this->root->rch=new Node(-INF); 167 this->root->rch->prt=this->root; 168 } 169 SplayTree(const std::vector<int>& v){ 170 this->root=Build(v,0,v.size()-1); 171 } 172 ~SplayTree(){ 173 delete this->root; 174 } 175 Node* Kth(int pos){ 176 ++pos; 177 Node* root=this->root; 178 while(root!=NULL){ 179 root->PushDown(); 180 int k=root->lch->size()+1; 181 if(pos<k) 182 root=root->lch; 183 else if(pos==k) 184 return root; 185 else{ 186 pos-=k; 187 root=root->rch; 188 } 189 } 190 return NULL; 191 } 192 inline int Sum(const int& pos,const int& len){ 193 this->Splay(this->Kth(pos-1)); 194 this->Splay(this->Kth(pos+len),this->root); 195 return this->root->rch->lch->sum(); 196 } 197 inline void Reverse(const int& pos,const int& len){ 198 this->Splay(this->Kth(pos-1)); 199 this->Splay(this->Kth(pos+len),this->root); 200 this->root->rch->lch->Swap(); 201 this->root->rch->Maintain(); 202 this->root->Maintain(); 203 } 204 inline void Set(const int& pos,const int& len,const int& d){ 205 this->Splay(this->Kth(pos-1)); 206 this->Splay(this->Kth(pos+len),this->root); 207 this->root->rch->lch->Set(d); 208 this->root->rch->Maintain(); 209 this->root->Maintain(); 210 } 211 inline void Insert(const int& pos,SplayTree* data){ 212 this->Splay(this->Kth(pos)); 213 this->Splay(this->Kth(pos+1),this->root); 214 Node* tmp=data->root; 215 data->root=NULL; 216 this->root->rch->lch=tmp; 217 tmp->prt=this->root->rch; 218 this->root->rch->Maintain(); 219 this->root->Maintain(); 220 } 221 inline void Delete(const int& pos,const int& len){ 222 this->Splay(this->Kth(pos-1)); 223 this->Splay(this->Kth(pos+len),this->root); 224 delete this->root->rch->lch; 225 this->root->rch->lch=NULL; 226 this->root->rch->Maintain(); 227 this->root->Maintain(); 228 } 229 inline int MaxSum(){ 230 return this->root->maxSum(); 231 } 232 void Print(){ 233 this->PrintTree(this->root,0); 234 } 235 }; 236 237 int FastRead(); 238 239 int main(){ 240 SplayTree* tree=new SplayTree(); 241 std::vector<int> v; 242 int n=FastRead(); 243 int m=FastRead(); 244 int a,b; 245 char buf[20]; 246 for(int i=0;i<n;i++){ 247 v.push_back(FastRead()); 248 } 249 tree->Insert(0,new SplayTree(v)); 250 for(int i=0;i<m;i++){ 251 scanf("%s",buf); 252 if(*buf!='M'||buf[2]!='X'){ 253 a=FastRead(); 254 b=FastRead(); 255 } 256 if(*buf=='G'){ 257 printf("%d\n",tree->Sum(a,b)); 258 } 259 else if(*buf=='D') 260 tree->Delete(a,b); 261 else if(*buf=='R') 262 tree->Reverse(a,b); 263 else if(*buf=='I'){ 264 v.clear(); 265 while(b--) 266 v.push_back(FastRead()); 267 tree->Insert(a,new SplayTree(v)); 268 } 269 else if(*buf=='M'){ 270 if(buf[2]=='K') 271 tree->Set(a,b,FastRead()); 272 else 273 printf("%d\n",tree->MaxSum()); 274 } 275 // tree->Print(); 276 } 277 return 0; 278 } 279 280 int FastRead(){ 281 int ans=0; 282 bool neg=false; 283 register char ch=getchar(); 284 while(!isdigit(ch)){ 285 if(ch=='-') 286 neg=true; 287 ch=getchar(); 288 } 289 while(isdigit(ch)){ 290 ans=ans*10+ch-'0'; 291 ch=getchar(); 292 } 293 if(neg) 294 ans=-ans; 295 return ans; 296 }
然后该放图了来着w
本博客已弃用, 新个人主页: https://rvalue.moe, 新博客: https://blog.rvalue.moe