zoukankan      html  css  js  c++  java
  • 酒店

    题目描述

    A城市有个超级大酒店,住房部只有一层,只向南,但房间有N个(编号1, 2 .. N)。刚开始所有房间都是空的,但酒店肯定会有人来住宿,有些房间就要被入住。但客人经常会问一个问题,最长连续的空房间是多少,因为客人想连续的住在一起。于是,有下列三个操作:

    1 a b:表示从房间a开始连续b个房间,将被入住(不管有没有人已经入住)

    2 a b:表示从房间a开始连续b个房间,将清空入住(不管有没有人入住)

    3:表示询问当前最长连续的空房间是多少?

    对于3的询问,输出相应答案。

    输入

    首先输入N和P,  N如问题描述,P表示有多少个操作

    然后输入P个操作

    输出

    对于第三种操作,输出相应答案

    样例输入

    12 10
    3
    1 2 3
    1 9 4
    3
    2 2 1
    3
    2 9 2
    3
    2 3 2
    3
    

    样例输出

    12
    4
    4
    6
    10
    

    提示

    【数据规模和约定】


    3<=N<=16,000


    3<=P<=200,000

     
     
    首先,大家都能看出来,这是一道线段树的题。
    那么除了常规的区记录间左右端点的数组,lazy数组,还要有一个数组sum[],表示所在区间内最长连续的空房间数。但是这并不够,在区间合并的时候很容易证明sum[now] = sum[now << 1] + sum[now << 1 | 1]是错的,这里不解释。
    所以对于每一个区间,还要维护两个值:一个是从左端点开始最长连续空房间数lmax,另一个是从右端点开始最长连续空房间数rmax,举个栗子:
    对于区间[1, 14]:
          1 2 3 4 5 6 7 8 9 10 11 12 13 14 
                   # # #                          #            
    '#' 为已经入住的个房间
    此时sum[now] = 6, lmax = 3, rmax = 1.
    那么对于维护sum[now],就可以得出
        sum[now] = max(sum[now << 1], sum[now << 1 | 1], rmax[now << 1] + lmax[now << 1 | 1])
    也就是说要考虑连个子区间的空房间刚好连在一块的情况。
     
    接下来就是想办法维护lmax[now]和rmax[now].
    这个也不难(但我还是智障了debug了好长时间),想清楚了就行了。
    拿lmax[now]举例,只要lmax[now << 1]是整个区间的长度的话,即now << 1整个区间都空,那么lmax[now] = lmax[now << 1] + lmax[now << 1 | 1],否则lmax[now] = lmax[now << 1].
     
    rmax[now]同理。
     
    最后想提一下lazy标记,和平时写的稍有些不同,不是累加的关系,而是将lazy[now]直接覆盖到lazy[now << 1]和lazy[now << 1 | 1]。因为对于一个房间只可能有入住和不入住两种情况,而这两种情况互不影响(题中描述如此:“不管有没有人已经入住”)。
     
    所以更新的函数就写出来了。
    更新,以及pushdown
     1 void pushdown(int now)
     2 {
     3     if(!a[now].lazy) return;
     4     a[now << 1].lazy = a[now << 1 | 1].lazy = a[now].lazy;
     5     a[now].lazy = 0;
     6     if(a[now].lazy == 2)        //清空入住 
     7     {
     8         a[now << 1].lmax = a[now << 1].rmax = a[now << 1].sum = a[now << 1].len;
     9         a[now << 1 | 1].lmax = a[now << 1 | 1].rmax = a[now << 1 | 1].sum = a[now << 1 | 1].len;
    10     }
    11     else
    12     {
    13         a[now << 1].lmax = a[now << 1].rmax = a[now << 1].sum = 0;
    14         a[now << 1 | 1].lmax = a[now << 1 | 1].rmax = a[now << 1 | 1].sum = 0;
    15     }
    16 }
    17 void update(int L, int R, int now, int d)
    18 {
    19     if(L == a[now].l && R == a[now].r)
    20     {
    21         if(d == 2) a[now].lmax = a[now].rmax = a[now].sum = R - L + 1;
    22         else a[now].lmax = a[now].rmax = a[now].sum = 0;
    23         a[now].lazy = d; return;        //直接覆盖lazy 
    24     }
    25     pushdown(now);
    26     int mid = (a[now].r + a[now].l) >> 1;
    27     if(R <= mid) update(L, R, now << 1, d);
    28     else if(L > mid) update(L, R, now << 1 | 1, d);
    29     else {update(L, mid, now << 1, d); update(mid + 1, R, now << 1 | 1, d);}
    30     a[now] = a[now << 1] + a[now << 1 | 1];            //因为用了结构体,所以这里重载了一下加号。 
    31 }

    啊对了,补一下定义的结构体和重载运算符

    struct Tree
    {
        int l, r, lazy, len;        //len:区间长度 
        int sum, lmax, rmax;
        /*其实这种封装也有一定的弊端,因为在重载加号的时候,返回的是一个新的结构体,
        所以必须对他的所有成员都赋上相应的值,否则会出错,具体看下方注释 */ 
        Tree operator + (const Tree& other)const
        {
            Tree ret;
            ret.sum = max(max(sum, other.sum), rmax + other.lmax);
            ret.l = l; ret.r = other.r;
            ret.len = ret.r - ret.l + 1;        //这就是容易疏忽的一点,我当时就忘了给len赋值,debug了1个多小时 
            if(lmax == len) ret.lmax = lmax + other.lmax;    //分情况维护lmax,rmax 
            else ret.lmax = lmax;
            if(other.rmax == other.len) ret.rmax = other.rmax + rmax;
            else ret.rmax = other.rmax;
            ret.lazy = 0;    //因为这条语句是在pushdown之后执行的,所以lazy已经被清空了 
            return ret;    
            /*如此看来,结构体里就应该有sum,lmax,rmax,因为其他都是不变的,或是在pushup操作里不需要的
            这么做也是尽量减少运算次数进行常数优化,但最重要的是,这样显得思维清晰,代码简练*/ 
        }
    }a[maxn << 2];

     对于查询,只用返回a[1].sum了,因为是全局查询。

    完整版代码

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<cctype>
      7 using namespace std;
      8 #define enter printf("
    ")
      9 #define space printf(" ")
     10 typedef long long ll;
     11 const int INF = 0x3f3f3f3f;
     12 const int maxn = 2e4 + 5;
     13 inline ll read()
     14 {
     15     ll ans = 0;
     16     char ch = getchar(), last = ' ';
     17     while(!isdigit(ch)) {last = ch; ch = getchar();}
     18     while(isdigit(ch))
     19     {
     20         ans = ans * 10 + ch - '0'; ch = getchar();    
     21     }
     22     if(last == '-') ans = -ans;
     23     return ans;
     24 }
     25 inline void write(ll x)
     26 {
     27     if(x < 0) x = -x, putchar('-');
     28     if(x >= 10) write(x / 10);
     29     putchar('0' + x % 10);
     30 }
     31 
     32 int n, p;
     33 
     34 struct Tree
     35 {
     36     int l, r, lazy, len;        
     37     int sum, lmax, rmax;
     38     Tree operator + (const Tree& other)const
     39     {
     40         Tree ret;
     41         ret.sum = max(max(sum, other.sum), rmax + other.lmax);
     42         ret.l = l; ret.r = other.r;
     43         ret.len = ret.r - ret.l + 1;        
     44         if(lmax == len) ret.lmax = lmax + other.lmax;    
     45         else ret.lmax = lmax;
     46         if(other.rmax == other.len) ret.rmax = other.rmax + rmax;
     47         else ret.rmax = other.rmax;
     48         ret.lazy = 0;    
     49         return ret;    
     50     }
     51 }a[maxn << 2];
     52 void build(int L, int R, int now)
     53 {
     54     a[now].l = L; a[now].r = R;
     55     a[now].sum = a[now].lmax = a[now].rmax = a[now].len = R - L + 1;
     56     a[now].lazy = 0;
     57     if(L == R) return;    
     58     int mid = (L + R) >> 1;
     59     build(L, mid, now << 1);
     60     build(mid + 1, R, now << 1 | 1);
     61 }
     62 void pushdown(int now)
     63 {
     64     if(!a[now].lazy) return;
     65     a[now << 1].lazy = a[now << 1 | 1].lazy = a[now].lazy;
     66     a[now].lazy = 0;
     67     if(a[now].lazy == 2)        
     68     {
     69         a[now << 1].lmax = a[now << 1].rmax = a[now << 1].sum = a[now << 1].len;
     70         a[now << 1 | 1].lmax = a[now << 1 | 1].rmax = a[now << 1 | 1].sum = a[now << 1 | 1].len;
     71     }
     72     else
     73     {
     74         a[now << 1].lmax = a[now << 1].rmax = a[now << 1].sum = 0;
     75         a[now << 1 | 1].lmax = a[now << 1 | 1].rmax = a[now << 1 | 1].sum = 0;
     76     }
     77 }
     78 void update(int L, int R, int now, int d)
     79 {
     80     if(L == a[now].l && R == a[now].r)
     81     {
     82         if(d == 2) a[now].lmax = a[now].rmax = a[now].sum = a[now].len;
     83         else a[now].lmax = a[now].rmax = a[now].sum = 0;
     84         a[now].lazy = d; return;        
     85     }
     86     pushdown(now);
     87     int mid = (a[now].r + a[now].l) >> 1;
     88     if(R <= mid) update(L, R, now << 1, d);
     89     else if(L > mid) update(L, R, now << 1 | 1, d);
     90     else {update(L, mid, now << 1, d); update(mid + 1, R, now << 1 | 1, d);}
     91     a[now] = a[now << 1] + a[now << 1 | 1];             
     92 }
     93 
     94 int main()
     95 {
     96     n = read(); p = read();
     97     build(1, n, 1);
     98     for(int i = 1; i <= p; ++i)
     99     {
    100         int d = read();
    101         if(d == 3) {write(a[1].sum); enter;} 
    102         else
    103         {
    104             int L = read(), add = read();
    105             update(L, L + add - 1, 1, d);
    106         }
    107     }
    108     return 0;
    109 }
  • 相关阅读:
    解决Ubuntu下pycharm无法输入中文的问题
    爬取www.mmjpg.com网站图片,你懂得哦!
    批量查询ip地址归属地
    Opencv源码编译
    使用阿里云安装python模块
    Ansible运维自动化
    Mha-Atlas-MySQL高可用
    SVN
    Tomcat
    DHCP
  • 原文地址:https://www.cnblogs.com/mrclr/p/9193408.html
Copyright © 2011-2022 走看看