zoukankan      html  css  js  c++  java
  • [POJ3667]Hotel(线段树,区间合并)

    题目链接:http://poj.org/problem?id=3667

    题意:有一个hotel有n间房子,现在有2种操作:

    1 a,check in,表示入住。需要a间连续的房子。返回尽量靠左的房间编号并更新。

    2 a b,check out,从a开始退房,一共退到a+b-1。

    seg数组l表示从左边开始数空房子的个数,r表示从右边数空房子的个数,s表示一共最多是有s个连续的空房子。

    add作为延迟标记有3种状态:-1表示不操作,0表示退房,1表示入住。

    pushUP:向上更新,需要更新seg[rt]的三个值,依据是seg[lrt]和seg[rrt]共计6个值。

    由于seg[rt]表示包括了seg[lrt]和seg[rrt]两个区间,那么一开始seg[rt].l=seg[lrt].l,seg[rt].r=seg[rrt].r是木有问题的,接下来要考虑两边合并后seg[lrt]的右和seg[rrt]的左链接起来的情况:

    当lrt的左起连续区间和lrt的整个长度相同的时候,说明这一整块都是连续区间,那必然会和rrt的左起最长连续区间连接在一起(当然这里说的连续区间是指的空房子)。所以要在这种情况下更新lrt;同理也要更新rrt。

    最后要更新rt的总计最长,即rt左起算最长区间和rt算右起最长区间。但是不要忘记lrt和rrt本身的最长区间seg[lrt].s和seg[rrt].s。

    pushDOWN:向下更新,目的是为了传递懒惰标记,这个比较简单。注意好add三个含义就行了,释放的时候需要将节点的三个值都归为下属区间的总长度。

    update:很常规。

    query:查询的时候尽可能靠左,判断三种情况:当前节点左儿子的最大连续区间大于等于要求区间长度、中间(seg[lrt].r+seg[rrt].l)大于等于要求区间长度、右儿子大于要求区间长度。

    左右儿子遍历即可,中间的话长度可以直接得到:mid此时应当作为向左遍历的右终点,但是无法再相左,所以应该是当前节点左儿子的从右计数开始的那段。起始编号即mid-seg[lrt].r+1。

      1 #include <algorithm>
      2 #include <iostream>
      3 #include <iomanip>
      4 #include <cstring>
      5 #include <climits>
      6 #include <complex>
      7 #include <cassert>
      8 #include <cstdio>
      9 #include <bitset>
     10 #include <vector>
     11 #include <deque>
     12 #include <queue>
     13 #include <stack>
     14 #include <ctime>
     15 #include <set>
     16 #include <map>
     17 #include <cmath>
     18 using namespace std;
     19 
     20 #define lrt rt << 1
     21 #define rrt rt << 1 | 1
     22 const int maxn = 50050;
     23 typedef struct Node {
     24     int s, l, r;
     25 }Node;
     26 
     27 int add[maxn<<2];
     28 Node seg[maxn<<2];
     29 int n, q, cmd;
     30 
     31 void build(int l, int r, int rt) {
     32     add[rt] = -1;
     33     seg[rt].s = seg[rt].l = seg[rt].r = r - l + 1;
     34     if(l == r) return;
     35     int mid = (l + r) >> 1;
     36     build(l, mid, lrt);
     37     build(mid+1, r, rrt);
     38 }
     39 
     40 void pushUP(int rt, int len) {
     41     seg[rt].l = seg[lrt].l;
     42     seg[rt].r = seg[rrt].r;
     43     if(seg[rt].l == len - len / 2) seg[rt].l += seg[rrt].l;
     44     if(seg[rt].r == len / 2) seg[rt].r += seg[lrt].r;
     45     seg[rt].s = max(max(seg[rt].l, seg[rt].r), max(seg[lrt].s, seg[rrt].s));
     46     seg[rt].s = max(seg[rt].s, seg[lrt].r+seg[rrt].l);
     47 }
     48 
     49 void pushDOWN(int rt, int len) {
     50     if(~add[rt]) {
     51         if(add[rt] != 0) {
     52             seg[lrt].s = seg[lrt].l = seg[lrt].r = 0;
     53             seg[rrt].s = seg[rrt].l = seg[rrt].r = 0;
     54         }
     55         else {
     56             seg[lrt].s = seg[lrt].l = seg[lrt].r = len - len / 2;
     57             seg[rrt].s = seg[rrt].l = seg[rrt].r = len / 2;
     58         }
     59         add[lrt] = add[rrt] = add[rt];
     60         add[rt] = -1;
     61     }
     62 }
     63 
     64 int query(int pos, int l, int r, int rt) {
     65     if(l == r) return 1;
     66     pushDOWN(rt, r-l+1);
     67     int mid = (l + r) >> 1;
     68     if(seg[lrt].s >= pos) return query(pos, l, mid, lrt);
     69     else if(seg[lrt].r + seg[rrt].l >= pos) return mid - seg[lrt].r + 1;
     70     else return query(pos, mid+1, r, rrt);
     71 }
     72 
     73 void update(int L, int R, int c, int l, int r, int rt) {
     74     if(L <= l && r <= R) {
     75         seg[rt].s = seg[rt].l = seg[rt].r = c ? 0 : r - l + 1;
     76         add[rt] = c;
     77         return;
     78     }
     79     pushDOWN(rt, r-l+1);
     80     int mid = (l + r) >> 1;
     81     if(L <= mid) update(L, R, c, l, mid, lrt);
     82     if(mid < R) update(L, R, c, mid+1, r, rrt);
     83     pushUP(rt, r-l+1);
     84 }
     85 
     86 int main() {
     87     // freopen("in", "r", stdin);
     88     int a, b;
     89     while(~scanf("%d %d", &n, &q)) {
     90         build(1, n, 1);
     91         for(int i = 0; i < q; i++) {
     92             scanf("%d", &cmd);
     93             if(cmd == 1) {
     94                 scanf("%d", &a);
     95                 if(a > seg[1].s) {
     96                     puts("0");
     97                     continue;
     98                 }
     99                 b = query(a, 1, n, 1);
    100                 printf("%d
    ", b);
    101                 update(b, a+b-1, 1, 1, n, 1);
    102             }
    103             else {
    104                 scanf("%d %d", &a, &b);
    105                 update(a, a+b-1, 0, 1, n, 1);
    106             }
    107         }
    108     }
    109     return 0;
    110 }
  • 相关阅读:
    c#中MessageBox的使用(转)
    ArcGIS中地图配准(转)
    VS2010中VC9.0Runtime与VC10.0Runtime在win7上装不上提示error code 1603(转)
    win7下安装Oracle 10G 的成功方法
    解决win 7 下打不开chm格式文件的办法
    vi 编辑器
    开源赚钱思路
    如何开始linux 编程
    Linux C语言开发基础
    如何做开源项目——ABC
  • 原文地址:https://www.cnblogs.com/kirai/p/5947305.html
Copyright © 2011-2022 走看看