• POJ 3667 Hotel


    题目大意:

    1 a:询问是不是有连续长度为a的空房间,有的话住进最左边

    2 a b:将[a,a+b-1]的房间清空

    思路:线段树的区间合并。

    用cov记录区段的状态,-1代表没有被更新,0代表空闲,1代表是有人入住的。

    用lmax代表从左端点开始最长的空闲区间,rmax代表从右开始最长的区间。tree代表自己这个区间内拥有的最大区间。

    接下来就是两个重要的函数:pushdown  pushup了

    void pushup(int num,int mid)
    {
        lmax[num]=lmax[num<<1];
        rmax[num]=rmax[num<<1|1];
        if(lmax[num]==(mid-(mid>>1)))lmax[num]+=lmax[num<<1|1];
        if(rmax[num]==(mid>>1))rmax[num]+=rmax[num<<1];
        tree[num]=max(tree[num<<1],max(tree[num<<1|1],rmax[num<<1]+lmax[num<<1|1]));
    }

    首先在不考虑左右最大区间重叠的情况下,左边最大区间是左儿子的最大左区间,右边的最大区间是又儿子的最大右区间。

    lmax[num]==(mid-(mid>>1))时,就代表左边全部是空闲的,就要考虑一个最大的区间被分成了两边了,就再加上右儿子的最大左区间。

    同理。

    最后更新最大区间的时候  就要三者做比较    最大的左  最大的右   左右之间的部分。

     

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define MAXN 50005
    using namespace std;
    
    int tree[MAXN<<2];
    int lmax[MAXN<<2];
    int rmax[MAXN<<2];
    int cov[MAXN<<2];
    
    void pushup(int num,int mid)
    {
        lmax[num]=lmax[num<<1];
        rmax[num]=rmax[num<<1|1];
        if(lmax[num]==(mid-(mid>>1)))lmax[num]+=lmax[num<<1|1];
        if(rmax[num]==(mid>>1))rmax[num]+=rmax[num<<1];
        tree[num]=max(tree[num<<1],max(tree[num<<1|1],rmax[num<<1]+lmax[num<<1|1]));
    }
    
    void pushdown(int num,int mid)
    {
        if(cov[num]!=-1)
        {
            cov[num<<1] = cov[num<<1|1] = cov[num];
            tree[num<<1] = lmax[num<<1] = rmax[num<<1] = cov[num] ? 0: (mid - (mid>>1));
            tree[num<<1|1] = lmax[num<<1|1] = rmax[num<<1|1] = cov[num] ? 0:(mid>>1);
            cov[num]=-1;
        }
    }
    
    
    void build(int num,int l,int r)
    {
        lmax[num] = rmax[num] = tree[num] = r - l + 1;
        cov[num] = -1;
        if(r==l)return;
        int mid = (r+l)>>1;
        build(num<<1,l,mid);
        build(num<<1|1,mid+1,r);
    }
    
    
    int query(int num,int s,int e,int w)
    {
        if(e==s)
        return s;
        pushdown(num,e-s+1);
        int mid = (s+e)>>1;
    
        if(tree[num<<1]>=w)return query(num<<1,s,mid,w);
        else if(rmax[num<<1] + lmax[num<<1|1] >=w)return mid + 1 - rmax[num<<1];
    
        return query(num<<1|1,mid+1,e,w);
    }
    
    void update(int num,int s,int e,int l,int r,int v)
    {
        if(l<=s && e<=r)
        {
            tree[num] = lmax[num] = rmax[num] = v ? 0 : e-s+1;
            cov[num] = v;
            return ;
        }
        pushdown(num,e-s+1);
        int mid = (e+s)>>1;
        if(l<=mid)update(num<<1,s,mid,l,r,v);
        if(r>mid)update(num<<1|1,mid+1,e,l,r,v);
        pushup(num,e-s+1);
    }
    
    
    int main()
    {
        int n,m;
    
            scanf("%d%d",&n,&m);
            build(1,1,n);
            for(int i=1;i<=m;i++)
            {
                int a,b,c;
                scanf("%d",&a);
    
                if(a==1)
                {
                    scanf("%d",&b);
                    if(tree[1]<b)puts("0");
                    else {
                    int p=query(1,1,n,b);
                    printf("%d
    ",p);
                    update(1,1,n,p,p+b-1,1);
                    }
                }
                else
                {
                    scanf("%d%d",&b,&c);
                    update(1,1,n,b,b+c-1,0);
                }
            }
            return 0;
    }
    
    


  • 相关阅读:
    c#泛型的使用
    关于Asp.net无法写入输出文件的原因
    利用OLEDB导出数据到Excel
    中秋祝福
    C#获取当前域用户名
    【程序员必读】骨灰级程序员20条编程经验
    SQL SERVER 2005无法远程连接的问题
    ASP.Net 实现伪静态方法及意义
    js+ajax获取文件大小
    C#遍历指定文件夹中的所有文件
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3201282.html
Copyright © 2020-2023  润新知