酒店

题目描述

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     else12     {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  2 #include  3 #include  4 #include  5 #include  6 #include  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         else103         {104             int L = read(), add = read();105             update(L, L + add - 1, 1, d);106         }107     }108     return 0;109 }

 

 

上一篇:合唱队形 ( 双向LIS )


下一篇:拦截导弹 (最长上升子序列LIS)