zoukankan      html  css  js  c++  java
  • ACWing 261 旅馆(Hotel)

    Problem(Description)

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

    • (1,d) 寻找到最左边的连续(d)(0)的序列,并全部变成(1)
    • (2,x,d)([x,x + d - 1])块全部变成(0)
      (1 le n,m le 50000)

    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
    ",x);
                    update(1,x,x + d - 1,1,n,1);
                }
                else printf("%d
    ",0);
            }
            else
            {
                scanf("%d%d",&x,&d);
                update(1,x,x + d - 1,1,n,-1);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    分子量 (Molar Mass,ACM/ICPC Seoul 2007,UVa 1586)
    [补档]各种奇怪的韩信问题
    [补档][HNOI 2008]GT考试
    [补档][Tyvj 1728]普通平衡树
    [补档][JLOI 2017]聪明的燕姿
    [补档][NOI 2008]假面舞会
    网络基础
    操作系统
    计算机硬件
    类和对象
  • 原文地址:https://www.cnblogs.com/luyiming123blog/p/14802509.html
Copyright © 2011-2022 走看看