其他分享
首页 > 其他分享> > ACWing 261 旅馆(Hotel)

ACWing 261 旅馆(Hotel)

作者:互联网

Problem(Description)

现在有一个长度为\(n\)的序列和\(m\)个操作,操作有两种:

Solution

Thinking 1

其实这个题就两个东西:

  1. 找到最左边的长度不小于\(d\)的最长\(0\)块
  2. 区间修改
    显然2可以用线段树做,1怎么做呢?

Thinking 2

想到洛谷 P4513 小白逛公园这一题,通过维护左边最长段,右边最长段和总最长段来确定,那么连续\(0\)块是不是也能这么做?

Thinking 3

设\(T[root].lmax\)为当前左边最长段,\(T[root].rmax\)同理,\(T[root].Max\)为总最长段。
在update时,如果是被完全包含的情况,若是add,那么三者全部变为0,否则全部变为这个节点的长度。
在pushdown的时候基本差不多,具体看代码。
pushup就是分别考虑更新当前节点的lmax,rmax和Max:
lmax:若左节点全部是0,那么lmax = l.Max + r.lmax; 否则lmax = l.lmax;
rmax:若右节点全部是0,那么rmax = r.Max + l.rmax; 否则rmax = r.rmax;
Max: 形如小白逛公园,Max = max(l.Max.r.Max,l.rmax + r.lmax);

然后query时根据情况二分即可。

# include <bits/stdc++.h>
using namespace std;
const int N = 50005;
int n,m;
struct node
{
    int val,lazy;
    int lmax,rmax,Max;
}T[N << 2];

void build(int root,int l,int r)
{
    if(l == r) 
    {
        T[root].val = T[root].lazy = 0,T[root].lmax = T[root].rmax = T[root].Max = 1;
        return;
    }
    int mid = (l + r) >> 1;build(root << 1,l,mid),build(root << 1 | 1,mid + 1,r);
    T[root].val = T[root << 1].val + T[root << 1 | 1].val,T[root].lmax = T[root].rmax = T[root].Max = (r - l + 1);
    return;
}

void pushdown(int root,int l,int r)
{
    if(T[root].lazy == 0) return;
    int mid = (l + r) >> 1;
    if(T[root].lazy == -1)
    {
        T[root << 1].lmax = T[root << 1].rmax = T[root << 1].Max = (mid - l + 1);
        T[root << 1 | 1].lmax = T[root << 1 | 1].rmax = T[root << 1 | 1].Max = (r - mid);
        T[root << 1].lazy = T[root << 1 | 1].lazy = -1;
    }
    else if(T[root].lazy == 1)
    {
        T[root << 1].lmax = T[root << 1].rmax = T[root << 1].Max = T[root << 1 | 1].lmax = T[root << 1 | 1].rmax = T[root << 1 | 1].Max = 0;
        T[root << 1].lazy = T[root << 1 | 1].lazy = 1;
    }
    T[root].lazy = 0;return;
}

void pushup(int root,int l,int r)
{
    int mid = (l + r) >> 1;
    if(T[root << 1].Max == (mid - l + 1)) // full 0
    {
        T[root].lmax = T[root << 1].Max + T[root << 1 | 1].lmax;
    }
    else T[root].lmax = T[root << 1].lmax;
    if(T[root << 1 | 1].Max == (r - mid))
    {
        T[root].rmax = T[root << 1 | 1].Max + T[root << 1].rmax;
    }
    else T[root].rmax = T[root << 1 | 1].rmax;
    T[root].Max = max(T[root << 1].Max,max(T[root << 1 | 1].Max,T[root << 1].rmax + T[root << 1 | 1].lmax));
    return;
}

void update(int root,int l,int r,int s,int t,int d)
{
    if(l <= s && t <= r)
    {
        if(d == 1) T[root].lmax = T[root].rmax = T[root].Max = 0;
        else T[root].lmax = T[root].rmax = T[root].Max = t - s + 1;
        T[root].lazy = d;
        return;
    }
    int mid = (s + t) >> 1;
    pushdown(root,s,t);
    if(l <= mid) update(root << 1,l,r,s,mid,d);
    if(r > mid) update(root << 1 | 1,l,r,mid + 1,t,d);
    pushup(root,s,t);
    return;
 }

 int query(int root,int l,int r,int d)
 {
     pushdown(root,l,r);
    //  pushup(root,l,r);
     if(l == r) return l;
    int mid = (l + r) >> 1;
    if(T[root << 1].Max >= d)
    {
        return query(root << 1,l,mid,d);
    }
    if(T[root << 1].rmax + T[root << 1 | 1].lmax >= d)
    {
        return mid - T[root << 1].rmax + 1;
    }
    else return query(root << 1 | 1,mid + 1,r,d);
 }

int main(void)
{
    scanf("%d%d",&n,&m);
    build(1,1,n);
    while(m--)
    {
        int d,x;
        int opt;scanf("%d",&opt);
        if(opt == 1)
        {
            scanf("%d",&d);
            if(T[1].Max >= d)
            {
                x = query(1,1,n,d);
                printf("%d\n",x);
                update(1,x,x + d - 1,1,n,1);
            }
            else printf("%d\n",0);
        }
        else
        {
            scanf("%d%d",&x,&d);
            update(1,x,x + d - 1,1,n,-1);
        }
    }
    return 0;
}

标签:int,Max,Hotel,rmax,lmax,update,261,root,ACWing
来源: https://www.cnblogs.com/luyiming123blog/p/14802509.html