Splay chapter 2: POJ 3667/BZOJ 1593

据说Splay最霸气的东西是它可以搞一些其他平衡树甚至其他树不能搞得东西 比如区间的操作 至少Treap就不行(FHQ请无视蒟蒻不懂您的Treap)

同时我发现 几乎所有线段树的题 Splay都能搞(但大部分属于自残行为) 所以我就去做了一道 USACO FEB08 的 经典题 真是够呛

Problem:

 

Hotel

 

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 8116   Accepted: 3447

 

Description

 

The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as their vacation residence. This immense hotel has N (1 ≤ N ≤ 50,000) rooms all located on the same side of an extremely long hallway (all the better to see the lake, of course).

The cows and other visitors arrive in groups of size Di (1 ≤ Di ≤ N) and approach the front desk to check in. Each group i requests a set of Di contiguous rooms from Canmuu, the moose staffing the counter. He assigns them some set of consecutive room numbers r..r+Di-1 if they are available or, if no contiguous set of rooms is available, politely suggests alternate lodging. Canmuu always chooses the value of r to be the smallest possible.

Visitors also depart the hotel from groups of contiguous rooms. Checkout i has the parameters Xi and Di which specify the vacating of rooms Xi ..Xi +Di-1 (1 ≤ Xi ≤ N-Di+1). Some (or all) of those rooms might be empty before the checkout.

Your job is to assist Canmuu by processing M (1 ≤ M < 50,000) checkin/checkout requests. The hotel is initially unoccupied.

 

Input

 

* Line 1: Two space-separated integers: N and M
* Lines 2..M+1: Line i+1 contains request expressed as one of two possible formats: (a) Two space separated integers representing a check-in request: 1 and D(b) Three space-separated integers representing a check-out: 2, Xi, and Di

 

Output

 

* Lines 1.....: For each check-in request, output a single line with a single integer r, the first room in the contiguous sequence of rooms to be occupied. If the request cannot be satisfied, output 0.

 

Sample Input

 

10 6
1 3
1 3
1 3
1 3
2 5 5
1 6

 

Sample Output

 

1
4
7
0
5

 

Source

 

 
solution:
      这题用线段树好像就不大好搞 它是要我们染色和询问白色线段 做得我很是恼火 但还好还是在脑补蒟蒻数据过了之后就1A了 所以以后做题还是要多自己YY 至少可以减少Debug时间
      对于每个房间 建成树上的节点 这里我YY了一个虚拟头和虚拟尾 方便成段染色 然后是猥琐的N多关键字 详见Code
      对于询问 就查找就行了 但是 注意查找的时候 push_down 要搞完 不然询问lr ll rl rr这些就没更新 完了之后找到左右开区间 标记
      对于操作 先查左右 然后 用经典的splay 把操作对象压到一颗子树 然后标记
      还要注意的就是每种操作后都要把对象子树的root旋根 这样一路上就直接upd了
 
Code:
View Code
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <iostream>
  7 #define rep(i,l,r) for(int i=l;i<=r;++i)
  8 using namespace std;
  9 const int oo = ~0U>>2;
 10 int n,m,a,b,cmd;
 11 class Splay{
 12     private:
 13       struct Node{
 14           int key,cnt;
 15           int lsum,rsum,sum,mark,size;
 16           bool v;
 17           Node *c[2],*fa;
 18           Node(int _key,Node *_fa){
 19             key = _key; fa = _fa; v = true; mark = size = 0;
 20             lsum = rsum = sum = cnt = 1; c[0] = c[1] = NULL;
 21           }
 22           inline int ll() {return c[0] ? c[0]->lsum : 0;}
 23           inline int lr() {return c[0] ? c[0]->rsum : 0;}
 24           inline int rl() {return c[1] ? c[1]->lsum : 0;}
 25           inline int rr() {return c[1] ? c[1]->rsum : 0;}
 26           inline int ls() {return c[0] ? c[0]->sum : 0;}
 27           inline int rs() {return c[1] ? c[1]->sum : 0;}
 28           inline int lsz() {return c[0] ? c[0]->size : 0;}
 29           inline int rsz() {return c[1] ? c[1]->size : 0;}
 30       };
 31       Node *root;
 32       inline void upd(Node *tag){
 33           if(!tag) return;
 34           tag->size = tag->cnt + tag->lsz() + tag->rsz();
 35           tag->lsum = tag->ll();
 36           if(tag->lsum == tag->lsz() && tag->v)
 37             tag->lsum += 1 + tag->rl();
 38           tag->rsum = tag->rr();
 39           if(tag->rsum == tag->rsz() && tag->v)
 40             tag->rsum += 1 + tag->lr();
 41           tag->sum = max(tag->ls(),tag->rs());
 42           if(tag->v) tag->sum = max(tag->sum,tag->lr() + 1 + tag->rl());
 43       }
 44       inline void push_down(Node *tag){
 45           if(!tag || !tag->mark) return;
 46           int val = tag->mark > 0 ? 1 : 0;
 47           tag->lsum = tag->rsum = tag->sum = val * tag->size; tag->v = val;
 48           if(tag->c[0]) tag->c[0]->mark = tag->mark;
 49           if(tag->c[1]) tag->c[1]->mark = tag->mark;
 50           tag->mark = 0;
 51       }
 52       inline void zig(Node *tag,int d){
 53           Node *f = tag->fa;
 54           int anti = 1 - d;
 55           push_down(tag->c[0]); push_down(tag->c[1]); push_down(f->c[anti]);
 56           f->c[d] = tag->c[anti];
 57           if(f->c[d])
 58             f->c[d]->fa = f;
 59           tag->fa = f->fa;
 60           if(f->fa->c[0] == f)
 61             f->fa->c[0] = tag;
 62           else
 63             f->fa->c[1] = tag;
 64           tag->c[anti] = f;
 65           f->fa = tag;
 66           upd(f);
 67       }
 68       inline int f(Node *tag){
 69           return tag->fa->c[1] == tag;
 70       }
 71       inline void splay(Node *tag,Node *goal){
 72           push_down(tag);
 73           while(tag->fa != goal){
 74              if(tag->fa->fa == goal)
 75                zig(tag,f(tag));
 76              else{
 77                if(f(tag->fa) == f(tag))
 78                  zig(tag->fa,f(tag->fa)),zig(tag,f(tag));
 79                else
 80                  zig(tag,f(tag)),zig(tag,f(tag));
 81              }
 82           }
 83           upd(tag);
 84       }
 85       inline Node *search(int key,int &d){
 86           Node *tag = root->c[0],*tmp = root; d = 0;
 87           push_down(tag);
 88           while(tag && tag->key != key){
 89              if(tag->key < key) tmp = tag,tag = tag->c[1];
 90              else tmp = tag,tag = tag->c[0];
 91              push_down(tag);
 92           }
 93           return tag ? tag : tmp;
 94       }
 95       inline int ask(int l,Node *tag){
 96           if(!tag) return 0;
 97           push_down(tag); push_down(tag->c[0]); push_down(tag->c[1]);
 98           if(tag->sum < l) return 0;
 99           if(tag->ls() >= l) return ask(l,tag->c[0]);
100           if(tag->v){
101             if(tag->lr() + 1 + tag->rl() >= l) 
102              if(tag->lr()) return tag->key - tag->lr();
103              else return tag->key;
104           }
105           return ask(l,tag->c[1]);
106       }
107     public:
108       Splay() {
109         root = new Node(19960628,NULL); Node *tmp = new Node(0,root); Node *tmp2 = new Node(oo,tmp);
110         root->c[0] = tmp; tmp->sum = tmp->lsum = tmp->rsum = tmp->v = tmp->cnt = 0;
111         tmp->c[1] = tmp2; tmp2->sum = tmp2->lsum = tmp2->rsum = tmp2->v = tmp2->cnt = 0;
112       }
113       void ready(int n){
114            Node *tag; int d;
115            splay(tag = search(0,d),root); splay(search(oo,d),tag);
116            rep(i,1,n){
117              Node *f = search(i,d);
118              Node *tmp = new Node(i,f);
119              f->c[d] = tmp; upd(tmp); upd(f);
120              splay(tmp,root);
121            }
122       }
123       void query(int l){
124            int tag = ask(l,root->c[0]); int d;
125            if(!tag) {printf("0\n"); return;}
126            Node *L = search(tag - 1,d); Node *R = search(tag + l <= n ? tag + l : oo,d);
127            splay(L,root); splay(R,L);
128            R->c[0]->mark --;
129            splay(R->c[0],root);
130            printf("%d\n",tag);
131       }
132       void erase(int x,int l){
133            int d;
134            Node *L = search(x - 1,d),*R = search(x + l <= n ? x + l : oo,d);
135            splay(L,root); splay(R,L);
136            R->c[0]->mark ++;
137            splay(R->c[0],root);
138       }
139 }tree;
140 int main()
141 {
142     freopen("input.in","r",stdin); freopen("output.out","w",stdout);
143     while(scanf("%d%d",&n,&m) != EOF){
144        tree.ready(n);
145        rep(i,1,m){
146          scanf("%d",&cmd);
147          if(cmd == 1){
148            scanf("%d",&a);
149            tree.query(a); continue;
150          }
151          if(cmd == 2){
152            scanf("%d%d",&a,&b);
153            tree.erase(a,b); continue;
154          }
155        }
156     }
157     return 0;
158 }

 

最后 我发现USACO的月赛 可以直接 点 http://contest.usaco.org 以后可以做做这个 完了

 

posted on 2012-12-13 21:50  _nardy  阅读(227)  评论(0编辑  收藏  举报