Poj 3667 - Hotel 线段树--区间合并

最近一直在看胡浩的【完全版】线段树,这个题目是在他的blog介绍的

 

文字没有参考别人的成分

 

题目大意:Hotel有N(1 ≤ N ≤ 50,000)间rooms,并且所有的rooms都是连续排列在同一边,groups需要check in 房间,要求房间的编号为连续的r..r+Di-1并且r是最小的;visitors同样可能check out,并且他们每次check out都是编号为Xi ..Xi +Di-1 (1 ≤ XiN-Di+1)的房间,题目的输入有两种样式:

  1. 1  a     :  groups需要check in  a间编号连续的房间
  2. 2  a   b : visitors  check out 房间,其中房间编号是 a…a+b-1

要求对于每次request,输出为groups分配数目为a的房间中编号最小的房间编号

 

思路:利用线段树建立模型,维护最大连续区间长度,其中区间长度就是对应的房间数目,并且对应区间中最左边的断点就是answer,同时因为需要求出连续区间的最大长度,因此每次PushUp时都将左右区间合并,lsum维护左区间的最大长度,rsum维护右区间的最大长度,sum维护区间1…N中的最大连续区间长度,cover标志对应区间是否为空(没有住客)

 

具体实现过程:

BuildTree:建立一颗线段树,其中lsum,rsum,sum初始化为对应区间的长度

Query   :询问是否有长度为a的连续区间,如果有,返回对应区间的最左边的断点

UpData  :更新线段树的信息

PushUp  :将左右子区间合并

PushDown :标志向下传,延迟标志,简单来说就是先标志,然后等到下次询问或者更新时再去更新线段树

 

代码:

  1 #include <stdio.h>
  2 
  3 #define lson l, m, rt<<1
  4 #define rson m+1, r, rt<<1|1
  5 
  6 const int maxn = 50000;
  7 
  8 int n, mNum, op, a, b;
  9 int sum[maxn*3], lsum[maxn*3], rsum[maxn*3], cover[maxn*3];
 10 
 11 void BuildTree(int l, int r, int rt)
 12 {
 13     cover[rt] = -1;
 14     lsum[rt] = rsum[rt] = sum[rt] = r-l+1;
 15     if (l == r)
 16         return ;
 17     
 18     int m = (l+r)>>1;
 19     BuildTree(lson);
 20     BuildTree(rson);
 21 }/* BuildTree */
 22 
 23 void PushDown(int rt, int k)
 24 {
 25     if (cover[rt] != -1)
 26     {   /* Lazy Tag */
 27         cover[rt<<1] = cover[rt<<1|1] = cover[rt];
 28         lsum[rt<<1] = rsum[rt<<1] = sum[rt<<1] = cover[rt] ? 0:(k-(k>>1)); 
 29         lsum[rt<<1|1] = rsum[rt<<1|1] = sum[rt<<1|1] = cover[rt] ? 0:(k>>1);
 30         cover[rt] = -1;
 31     }
 32 }/* PushDown */
 33 
 34 int query(int w, int l, int r, int rt)
 35 {
 36     if (l == r)
 37         return 1;
 38     
 39     PushDown(rt, r-l+1);    /* Push Down */
 40     
 41     int m = (l+r)>>1;
 42     if (sum[rt<<1] >= w)    /* 左连续区间长度 */ 
 43         return query(w, lson);
 44     else if (rsum[rt<<1]+lsum[rt<<1|1] >= w) /* 左区间后半部分与右区间左半部分长度 */ 
 45         return m-rsum[rt<<1]+1;
 46     else                    /* 右连续区间长度 */ 
 47         return query(w, rson);
 48 }/* query */
 49 
 50 int Max(int x, int y)
 51 {
 52     return (x>y ? x:y);
 53 }/* Max */
 54 
 55 void PushUp(int rt, int k)
 56 {
 57     lsum[rt] = lsum[rt<<1];   /* 左区间的左半部分 */ 
 58     rsum[rt] = rsum[rt<<1|1]; /* 右区间的右半部分 */ 
 59     
 60     if (lsum[rt] == k-(k>>1))
 61         lsum[rt] += lsum[rt<<1|1];
 62     if (rsum[rt] == k>>1)
 63         rsum[rt] += rsum[rt<<1];
 64     
 65     sum[rt] = Max(rsum[rt<<1]+lsum[rt<<1|1], Max(sum[rt<<1], sum[rt<<1|1]));
 66 }/* PushUp */
 67 
 68 void UpData(int L, int R, int c, int l, int r, int rt)
 69 {
 70     if (L<=l && r<=R)
 71     {
 72         lsum[rt] = rsum[rt] = sum[rt] = c ? 0 : r-l+1;
 73         cover[rt] = c;
 74         
 75         return ;
 76     }/* End of If */
 77     
 78     PushDown(rt, r-l+1);    /* Push Down */
 79     
 80     int m = (l+r)>>1;
 81     if (L <= m)
 82         UpData(L, R, c, lson);
 83     if (R > m)
 84         UpData(L, R, c, rson);
 85     
 86     PushUp(rt, r-l+1);      /* Push Up */
 87 }/* Updata */
 88 
 89 int main()
 90 {
 91     scanf("%d %d", &n, &mNum);
 92     
 93     BuildTree(1, n, 1); /* BuildTree */ 
 94     for (int i=1; i<=mNum; ++i)
 95     {
 96         scanf("%d", &op);
 97         if (op == 1)
 98         {   // Request
 99             scanf("%d", &a);
100             if (sum[1] < a)
101                 printf("0\n");  /* No result */
102             else
103             {
104                 int pos = query(a, 1, n, 1);
105                 printf("%d\n", pos);
106                 UpData(pos, pos+a-1, 1, 1, n, 1);   /* UpData the interval */
107             }
108         }/* End of If */
109         else
110         {
111             scanf("%d %d", &a, &b);
112             UpData(a, a+b-1, 0, 1, n, 1);   /* UpData the interval */
113         }
114     }/* End of For */
115     
116     return 0;
117 }

 

posted @ 2012-05-05 08:41  Maxwell:My Blog  阅读(6278)  评论(3编辑  收藏  举报