终于把区间操作的Splay搞明白了……
Splay的大致框架是这样的:
1 template <class T> 2 struct SplayNode 3 { 4 typedef SplayNode<T> Node; 5 Node* lch; 6 Node* rch; 7 Node* parent; 8 T val; 9 10 SplayNode(const T& _val,Node* _parent): 11 lch(0),rch(0),parent(_parent),val(_val) {} 12 13 void passDown() {} 14 void update() {} 15 16 void lRotate() 17 { 18 if(parent->parent) 19 { 20 if(parent==parent->parent->lch) 21 parent->parent->lch=this; 22 else parent->parent->rch=this; 23 } 24 25 parent->passDown(); 26 passDown(); 27 28 parent->rch=this->lch; 29 if(lch) lch->parent=this->parent; 30 31 lch=parent; 32 parent=parent->parent; 33 lch->parent=this; 34 35 lch->update(); 36 update(); 37 } 38 39 void rRotate() 40 { 41 if(parent->parent) 42 { 43 if(parent==parent->parent->lch) 44 parent->parent->lch=this; 45 else parent->parent->rch=this; 46 } 47 48 parent->passDown(); 49 passDown(); 50 51 parent->lch=this->rch; 52 if(rch) rch->parent=this->parent; 53 54 rch=parent; 55 parent=parent->parent; 56 rch->parent=this; 57 58 rch->update(); 59 update(); 60 } 61 62 Node* splay() 63 { 64 while(parent) 65 { 66 int status=0; 67 if(this==parent->lch) status|=1; else status|=2; 68 if(parent->parent) 69 { 70 if(parent==parent->parent->lch) status|=4; 71 else status|=8; 72 } 73 74 switch(status) 75 { 76 case 1: rRotate(); break; 77 case 2: lRotate(); break; 78 case 5: parent->rRotate(); this->rRotate(); break; 79 case 6: lRotate(); rRotate(); break; 80 case 9: rRotate(); lRotate(); break; 81 case 10: parent->lRotate(); this->lRotate(); break; 82 } 83 } 84 return this; 85 } 86 };
注意双旋的Zig-Zig(Zag-Zag)和Zig-Zag(Zag-Zig),后者可以分解成两次单旋,而前者不能。
借教室一题的75分代码(Vijos):
(Splay果然常数大……当然很可能是我写萎了……)
1 #include <algorithm> 2 3 using std::max; 4 using std::min; 5 6 struct SplayNode 7 { 8 typedef SplayNode Node; 9 Node* lch; 10 Node* rch; 11 Node* parent; 12 13 int idx; 14 int val; 15 int minVal; 16 int lazyTag; 17 18 SplayNode(int _idx,int _val,Node* _parent): 19 lch(0),rch(0),parent(_parent),idx(_idx),val(_val), 20 minVal(_val),lazyTag(0) {} 21 22 int actual() { return minVal + lazyTag; } 23 24 void passDown() 25 { 26 if(!lazyTag) return; 27 28 if(lch) lch->lazyTag += this->lazyTag; 29 if(rch) rch->lazyTag += this->lazyTag; 30 31 val += lazyTag; 32 minVal += lazyTag; 33 lazyTag = 0; 34 } 35 36 void update() 37 { 38 minVal = lch ? 39 ( rch ? min(min(lch->actual(),rch->actual()),this->val) : 40 min(lch->actual(),this->val) ) : 41 ( rch ? min(rch->actual(),this->val) : this->val ); 42 } 43 44 void lRotate() 45 { 46 if(parent->parent) 47 { 48 if(parent==parent->parent->lch) 49 parent->parent->lch=this; 50 else parent->parent->rch=this; 51 } 52 53 parent->passDown(); 54 passDown(); 55 56 parent->rch=this->lch; 57 if(lch) lch->parent=this->parent; 58 59 lch=parent; 60 parent=parent->parent; 61 lch->parent=this; 62 63 lch->update(); 64 update(); 65 } 66 67 void rRotate() 68 { 69 if(parent->parent) 70 { 71 if(parent==parent->parent->lch) 72 parent->parent->lch=this; 73 else parent->parent->rch=this; 74 } 75 76 parent->passDown(); 77 passDown(); 78 79 parent->lch=this->rch; 80 if(rch) rch->parent=this->parent; 81 82 rch=parent; 83 parent=parent->parent; 84 rch->parent=this; 85 86 rch->update(); 87 update(); 88 } 89 90 Node* splay() 91 { 92 while(parent) 93 { 94 int status=0; 95 if(this==parent->lch) status|=1; else status|=2; 96 if(parent->parent) 97 { 98 if(parent==parent->parent->lch) status|=4; 99 else status|=8; 100 } 101 102 switch(status) 103 { 104 case 1: rRotate(); break; 105 case 2: lRotate(); break; 106 case 5: parent->rRotate(); this->rRotate(); break; 107 case 6: lRotate(); rRotate(); break; 108 case 9: rRotate(); lRotate(); break; 109 case 10: parent->lRotate(); this->lRotate(); break; 110 } 111 } 112 return this; 113 } 114 }; 115 116 const int maxN=1e6+5; 117 118 SplayNode* node[maxN]; 119 int n,m; 120 121 int change(int d,int s,int t) 122 { 123 int status=0; 124 if(s==1) status |= 1; 125 if(t==n) status |= 2; 126 127 switch(status) 128 { 129 case 0: 130 node[s-1]->splay(); 131 node[s-1]->rch->parent=0; 132 node[t+1]->splay(); 133 node[s-1]->rch=node[t+1]; 134 node[t+1]->parent=node[s-1]; 135 136 node[t+1]->lch->lazyTag -= d; 137 node[t+1]->update(); 138 node[s-1]->update(); 139 return s-1; 140 case 1: 141 node[t+1]->splay(); 142 node[t+1]->lch->lazyTag -= d; 143 node[t+1]->update(); 144 return t+1; 145 case 2: 146 node[s-1]->splay(); 147 node[s-1]->rch->lazyTag -= d; 148 node[s-1]->update(); 149 return s-1; 150 case 3: 151 node[1]->splay(); 152 node[1]->val -= d; 153 node[1]->minVal -= d; 154 if(node[1]->rch) node[1]->rch->lazyTag -= d; 155 return 1; 156 } 157 } 158 159 #include <cstdarg> 160 #include <cstdio> 161 #include <cctype> 162 163 void readInt(int argCnt,...) 164 { 165 va_list va; 166 va_start(va,argCnt); 167 168 while(argCnt--) 169 { 170 int* dest=va_arg(va,int*); 171 int destVal=0; 172 char curDigit; 173 174 do curDigit=getchar(); while(!isdigit(curDigit)); 175 while(isdigit(curDigit)) 176 { 177 destVal = destVal * 10 + curDigit - ‘0‘; 178 curDigit=getchar(); 179 } 180 *dest=destVal; 181 } 182 183 va_end(va); 184 } 185 186 int main() 187 { 188 readInt(2,&n,&m); 189 int r; 190 readInt(1,&r); 191 node[1]=new SplayNode(1,r,0); 192 193 for(int i=2;i<=n;i++) 194 { 195 readInt(1,&r); 196 node[i]=new SplayNode(i,r,node[i-1]); 197 node[i-1]->rch=node[i]; 198 } 199 200 for(int i=1;i<=m;i++) 201 { 202 int d,s,t; 203 readInt(3,&d,&s,&t); 204 int rt=change(d,s,t); 205 if(node[rt]->minVal<0) 206 { 207 printf("-1\n%d",i); 208 return 0; 209 } 210 } 211 printf("0"); 212 return 0; 213 }
对于这道题,我们需要给每个Node额外设立3个域:idx(教室的标号,作为键值),minVal(子树中val的最小值),和lazyTag(修改的懒惰标记)
对区间[L,R]进行修改时,首先将L-1提到根,然后将R+1提到根的右孩子处,那么R+1的左孩子就是待修改的区间
当然要特判L==1和R==n(即左/右端为边界的情况)
注意旋转过程中要不断下传lazyTag并对节点的minVal值更新
(这个超级麻烦,一定要把每个细节都想全了,稍有一点疏忽就会出错,而且很不好查)
询问时直接询问根节点的minVal值即可(注意要让根节点的lazyTag传下去)
时间: 2024-10-29 19:07:52