酒店

题目描述

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("\n")
  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 }

 

 

posted @ 2018-06-17 18:27  mrclr  阅读(277)  评论(0编辑  收藏  举报