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 }

 

posted @ 2017-03-20 22:03  阿波罗2003  阅读(338)  评论(0编辑  收藏  举报