bzoj 3600 没有人的算术 - 替罪羊树 - 线段树
题目都是图片,就不给了,就给链接好了
由于bzoj比较慢,就先给[vjudge传送门]
有兴趣的可以去逛bzoj[bzoj传送门]
题目大意
有n个数a[1],a[2],...,a[n],它们开始都是0,现在有两种操作
1)C l r k,给a[k]赋值为(a[l], a[r])
2)Q l r,找到a[l], a[l + 1], ..., a[r]中的最大值,并输出它的下标,如果有多个最大值,则输出最小的那一个。
对于数对的比较,在题目中是这么定义的
对于任意x, y,若x = 0, y ≠ 0,则有x < y,例如,0 < (0, 0), 0 < (0, (0, 0))
对于任意数对x, y,若x ≠ 0, y ≠ 0,则先比较第一关键字,再比较第二关键字,因为题目中的数对是递归定义的,所以比较起来可能有点麻烦,例如(0, 0) < (0, (0, (0, 0))), (((0, (0, 0)), (0, 0)), 0) > ((0, 0), (0, 0)), 0)
解题思路
先想一下暴力吧,暴力想不出来想正解可能有点困难。暴力思路很简单,线段树维护区间最大值,递归比较,虽然会T掉,但是方法可以优化。
我可以考虑将这些数映射到一个实数区间$[0, 1]$上,让平衡树的每一个节点代表一个实数区间(想想为什么,不然再插一个节点到它下面,这个实数值怎么算?)。进行比较当在生成一个数的时候,我把它插进平衡树里,返回一个它的实数值。这样就可以实现$O(1)$比较。
至于用哪种平衡树呢,有待思考。我们知道很多平衡树在维护自己的平衡时通常会变得乱糟糟的,因此这个实数区间如果按照原来的实数区间继续做的话会出问题,比如旋转,左端点更小的旋转上来了,这个怎么玩。。一看就会出问题。。所以必须重新计算实数区间。现在作这样规定,若父节点的实数区间为$[vl, vr]$,则它的左子树的实数区间为$[vl, \frac{vl + vr}{2}]$,右子树的实数区间为$[\frac{vl + vr}{2}]$,如果你高兴,可以把$2$改成$3$。
假设我们用Splay来维护这个映射,当我们插入一个节点或者查询一次岂不是就要重新计算整个树的实数区间吗?也就是说还不如上面的暴力。所以需要重量平衡树,比如替罪羊树。替罪羊树在重构的时候可以顺便把实数区间处理出来。由于重构后对应数对的实数值(就去这个区间的mid吧)也会改变,所以之前的返回实数不可行,只能返回对应的节点,大不了比较的时候多写几行代码。因为替罪羊树深度有保证,所以精度不会炸。
接着再按返回回来的节点代表的实数值作比较,用线段树维护区间最大值,最大值的下标。再开一个数组记录一下对应位上当前映射到的节点上,这样对于修改操作不会那么麻烦。
另外,平衡因子取0.75左右比较快。
(其实这个东西是超现实数,可以建立和实数的一一映射)
Code(超级不简洁的代码)
1 /** 2 * bzoj 3 * Problem#3600 4 * Accepted 5 * Time:8420ms 6 * Memory:18584k 7 */ 8 #include<iostream> 9 #include<fstream> 10 #include<cstdio> 11 #include<ctime> 12 #include<cctype> 13 #include<cstring> 14 #include<cstdlib> 15 #include<fstream> 16 #include<sstream> 17 #include<algorithm> 18 #include<map> 19 #include<set> 20 #include<queue> 21 #include<vector> 22 #include<stack> 23 using namespace std; 24 typedef bool boolean; 25 #define inf 0xfffffff 26 #define smin(a, b) a = min(a, b) 27 #define smax(a, b) a = max(a, b) 28 template<typename T> 29 inline void readInteger(T& u){ 30 char x; 31 int aFlag = 1; 32 while(!isdigit((x = getchar())) && x != '-'); 33 if(x == '-'){ 34 x = getchar(); 35 aFlag = -1; 36 } 37 for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0'); 38 ungetc(x, stdin); 39 u *= aFlag; 40 } 41 42 template<typename T> 43 class Pair { 44 public: 45 T l, r; 46 Pair(T l = NULL, const T r = NULL):l(l), r(r) { } 47 48 boolean operator < (Pair b) { 49 if(l->val != b.l->val) return l->val < b.l->val; 50 return r->val < b.r->val; 51 } 52 }; 53 54 #define Node ScapegoatTreeNode* 55 typedef class ScapegoatTreeNode { 56 private: 57 const static double factor = 0.73; 58 public: 59 double l, r; 60 double val; 61 ScapegoatTreeNode* next[2]; 62 Pair<Node> p; 63 int s; 64 65 ScapegoatTreeNode():l(0), r(0), val(0), s(0) { 66 next[0] = next[1] = NULL; 67 } 68 ScapegoatTreeNode(double l, double r, Pair<Node> p):l(l), r(r), val((l + r) / 2), s(1), p(p) { 69 next[0] = next[1] = NULL; 70 } 71 72 void maintain() { 73 s = 1; 74 for(int i = 0; i < 2; i++) 75 if(next[i]) 76 s += next[i]->s; 77 } 78 79 boolean bad() { 80 for(int i = 0; i < 2; i++) 81 if(next[i] && next[i]->s > (s + 4) * factor) 82 return true; 83 return false; 84 } 85 }ScapegoatTreeNode; 86 87 typedef class ScapegoatTree { 88 public: 89 ScapegoatTreeNode* root; 90 vector<ScapegoatTreeNode*> lis; 91 92 ScapegoatTree():root(NULL) { } 93 94 void travel(ScapegoatTreeNode*& node) { 95 if(node->next[0] != NULL) travel(node->next[0]); 96 lis.push_back(node); 97 if(node->next[1] != NULL) travel(node->next[1]); 98 node->next[0] = node->next[1] = NULL; 99 node->s = 1; 100 } 101 102 ScapegoatTreeNode* rebuild(int l, int r, double vl, double vr) { 103 if(l > r) return NULL; 104 int mid = (l + r) >> 1; 105 ScapegoatTreeNode*& node = lis[mid]; 106 double vmid = (vl + vr) / 2; 107 node->l = vl, node->r = vr, node->val = vmid; 108 node->next[0] = rebuild(l, mid - 1, vl, vmid); 109 node->next[1] = rebuild(mid + 1, r, vmid, vr); 110 node->maintain(); 111 return node; 112 } 113 114 void remake(ScapegoatTreeNode*& node, ScapegoatTreeNode*& father) { 115 lis.clear(); 116 travel(node); 117 int l = 0, r = lis.size() - 1; 118 ScapegoatTreeNode*& newroot = lis[(l + r) >> 1]; 119 rebuild(l, r, node->l, node->r); 120 if(father != NULL) father->next[(father->next[0] == node) ? (0) : (1)] = newroot; 121 else this->root = newroot; 122 } 123 124 ScapegoatTreeNode* insert(ScapegoatTreeNode*& node, double vl, double vr, Pair<Node> p, ScapegoatTreeNode*& bad, ScapegoatTreeNode*& bf) { 125 double vmid = (vl + vr) / 2; 126 if(node == NULL) { 127 node = new ScapegoatTreeNode(vl, vr, p); 128 return node; 129 } 130 if(node->p.l->val == p.l->val && node->p.r == p.r) return node; 131 ScapegoatTreeNode* ret; 132 if(p < node->p) ret = insert(node->next[0], vl, vmid, p, bad, bf); 133 else ret = insert(node->next[1], vmid, vr, p, bad, bf); 134 if(bad != NULL && bf == NULL) bf = node; 135 if(node->bad()) bad = node, bf = NULL; 136 node->maintain(); 137 return ret; 138 } 139 140 ScapegoatTreeNode* insert(Pair<Node> p) { 141 ScapegoatTreeNode* bad = NULL, *fa = NULL, *ret; 142 ret = insert(root, 0.0, 1.0, p, bad, fa); 143 if(bad != NULL) remake(bad, fa); 144 return ret; 145 } 146 }ScapegoatTree; 147 148 ScapegoatTreeNode zero(0, 0, Pair<Node>()); 149 Pair<Node> pzero(&zero, &zero); 150 151 typedef class SegTreeNode { 152 public: 153 Node val; 154 int maxid; 155 SegTreeNode* l, *r; 156 SegTreeNode(Node val = NULL, SegTreeNode* l = NULL, SegTreeNode* r = NULL):val(val), l(l) ,r(r) { } 157 158 inline void pushUp() { 159 if(r->val->val < l->val->val) 160 val = l->val, maxid = l->maxid; 161 else if(l->val->val < r->val->val) val = r->val, maxid = r->maxid; 162 else val = l->val, maxid = l->maxid; 163 } 164 }SegTreeNode; 165 166 typedef class SegTree { 167 public: 168 SegTreeNode* root; 169 170 SegTree():root(NULL) { } 171 SegTree(int size){ 172 build(root, 1, size); 173 } 174 175 void build(SegTreeNode*& node, int l, int r) { 176 node = new SegTreeNode(); 177 if(l == r) { 178 node->val = &zero; 179 node->maxid = l; 180 return; 181 } 182 int mid = (l + r) >> 1; 183 build(node->l, l, mid); 184 build(node->r, mid + 1, r); 185 node->pushUp(); 186 } 187 188 void update(SegTreeNode*& node, int l, int r, Node val, int index) { 189 if(l == index && r == index) { 190 node->val = val; 191 return; 192 } 193 int mid = (l + r) >> 1; 194 if(index <= mid) 195 update(node->l, l, mid, val, index); 196 else update(node->r, mid + 1, r, val, index); 197 node->pushUp(); 198 } 199 200 void query(SegTreeNode*& node, int l, int r, int ql, int qr, Node& maxv, int& index) { 201 if(l == ql && r == qr) { 202 if(maxv->val < node->val->val) { 203 maxv = node->val; 204 index = node->maxid; 205 } else if(maxv->val == node->val->val) 206 smin(index, node->maxid); 207 return; 208 } 209 int mid = (l + r) >> 1; 210 if(qr <= mid) query(node->l, l, mid, ql, qr, maxv, index); 211 else if(ql > mid) query(node->r, mid + 1, r, ql, qr, maxv, index); 212 else { 213 query(node->l, l, mid, ql, mid, maxv, index); 214 query(node->r, mid + 1, r, mid + 1, qr, maxv, index); 215 } 216 } 217 218 int query(int l, int r, int n) { 219 Node maxv = &zero; 220 int index = inf; 221 query(root, 1, n, l, r, maxv, index); 222 return index; 223 } 224 }SegTree; 225 226 int n, m; 227 ScapegoatTree vm; 228 SegTree st; 229 Node* lis; 230 char buf[5]; 231 232 inline void init() { 233 readInteger(n); 234 readInteger(m); 235 st = SegTree(n); 236 lis = new Node[(const int)(n + 1)]; 237 for(int i = 1; i <= n; i++) 238 lis[i] = &zero; 239 } 240 241 inline void solve() { 242 for(int i = 1, a, b, c; i <= m; i++) { 243 scanf("%s%d%d", buf, &a, &b); 244 if(buf[0] == 'C') { 245 readInteger(c); 246 lis[c] = vm.insert(Pair<Node>(lis[a], lis[b])); 247 st.update(st.root, 1, n, lis[c], c); 248 } else { 249 printf("%d\n", st.query(a, b, n)); 250 } 251 } 252 } 253 254 int main() { 255 init(); 256 solve(); 257 return 0; 258 }