POJ 3667 Hotel(线段树区间合并)

题意:

给出n个房间,m个操作,操作有两种
操作1:需要x个连续的房间,如果存在则输出开始的房间,并占用,要求尽量小,没有的话则输出0.
操作2:从x开始的连续y个房间,解除占用。

关于区间合并:

区间合并问题一般是要求满足条件的一段连续的区间,个人觉得这类问题一个精华所在就是线段树的pushup函数的写法,如下:

/*ls表示区间的满足条件最长连续前缀,rs表示最长连续后缀,
ms表示该区间的最长连续序列。*/
void pushup(int l,int r,int rt)
{
    int m=(r+l)>>1;
    ls[rt]=ls[rt<<1];
    if(ls[rt<<1]==m-l+1) ls[rt]+=ls[rt<<1|1];
    rs[rt]=rs[rt<<1|1];
    if(rs[rt<<1|1]==r-m) rs[rt]+=rs[rt<<1];
    ms[rt]=max(max(ms[rt<<1],ms[rt<<1|1]),rs[rt<<1]+ls[rt<<1|1]);
    //在左边区间还是右边区间或者是跨区间
}

在这类问题种我们需要维护三个值,ls、rs、ms数组。我们要求的是区间内的最长连续序列,跟它的前缀和后缀又有什么关系呢?这就涉及到区间合并了。
一段区间的最长连续序列有三种情况:
第一种:最长连续序列起点和终点都在左区间,也就是只跟左区间有关。ms[rt<<1] 是一个候选人。
第二种:都在右区间。ms[rt<<1|1]是一个候选人。
第三种:起点在左区间,终点在右区间,那么这个区间长度就是左区间后缀加上右区间前缀,就用到了前缀和后缀。
对于每一个结点,都按照这样的方式去维护三个值,这样的方法就是解决这类问题的基本方法了。

思路:

本题其实就是求区间最长连续0序列。
修改操作是比较好实现的,解除占用只要将区间的ls、rs、ms修改为本区间的长度即可,因为区间全部变为了0,以上三个值都是区间长度。
接下来就是询问操作,首先将区间的最长连续序列与所需要的连续房间相比较,如果ms[1],就是整个区间的最长连续序列都不能满足,直接输出0.如果可以那么一定有区间可以满足。
依然是三种情况,因为要求房间最小,从左到右判断。
先是左区间满不满足,满足则深入左区间,答案就在左区间。
否则就是跨区间,如果满足可以直接返回第一个房间的位置。
然后就是右区间。
递归的结束是跨区间,因为每一个连续的区间都可以分成跨区间或者就是l==r这个情况是开一个房间,这里讲的有点迷,写的时候讨论所有情况这也就自然写出来了。

代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long ll;
const int maxn=5e4+10;
int ls[maxn<<2],rs[maxn<<2],ms[maxn<<2],col[maxn<<2];
int n,m;
/*区间合并正常pushup*/
void pushup(int l,int r,int rt)
{
    int m=(r+l)>>1;
    ls[rt]=ls[rt<<1];
    if(ls[rt<<1]==m-l+1) ls[rt]+=ls[rt<<1|1];
    rs[rt]=rs[rt<<1|1];
    if(rs[rt<<1|1]==r-m) rs[rt]+=rs[rt<<1];
    ms[rt]=max(max(ms[rt<<1],ms[rt<<1|1]),rs[rt<<1]+ls[rt<<1|1]);
}
void pushdown(int l,int r,int rt)
{
    int m=(r+l)>>1;
    if(col[rt]!=-1)
    {
        /*分0和1两种情况*/
        col[rt<<1]=col[rt<<1|1]=col[rt];
        if(col[rt]==0)
        {
            ls[rt<<1]=rs[rt<<1]=ms[rt<<1]=0;
            ls[rt<<1|1]=rs[rt<<1|1]=ms[rt<<1|1]=0;
        }
        else if(col[rt]==1)
        {
            ls[rt<<1]=rs[rt<<1]=ms[rt<<1]=m-l+1;
            ls[rt<<1|1]=rs[rt<<1|1]=ms[rt<<1|1]=r-m;
        }
        col[rt]=-1;//记得修改为-1
    }
}
void build(int l,int r,int rt)
{
    col[rt]=-1;
    int m=(r+l)>>1;
    if(l==r)
    {
        ls[rt]=rs[rt]=ms[rt]=1;
        return;
    }
    build(lson);
    build(rson);
    pushup(l,r,rt);//向上更新
    return;
}
/*正常区间修改*/
void updata(int ql,int qr,int c,int l,int r,int rt)
{
    int m=(r+l)>>1;
    if(ql<=l&&r<=qr)
    {
        ls[rt]=rs[rt]=ms[rt]=c*(r-l+1);//乘上区间长度
        col[rt]=c;
        return;
    }
    pushdown(l,r,rt);
    if(ql<=m) updata(ql,qr,c,lson);
    if(m<qr) updata(ql,qr,c,rson);
    pushup(l,r,rt);
}
/*因为要找最左边的,所以先看左区间的最大值是不是符合如果符合就深入左区间。
如果不符合就看跨区间的情况。
再不行就深入右区间。
如果w=1的话会搜索到l==r。递归结束条件l==r或者跨区间*/
int query(int w,int l,int r,int rt)
{
    int m=(r+l)>>1;
    if(l==r) return l;
    pushdown(l,r,rt);
    if(ms[rt<<1]>=w) return query(w,lson);//,除了1个的情况,总会转到跨区间的情况
    else if(rs[rt<<1]+ls[rt<<1|1]>=w) return m-rs[rt<<1]+1;
    return query(w,rson);
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    build(1,n,1);
    for(int i=1;i<=m;i++)
    {
        int op;
        scanf("%d",&op);
        if(op==1)
        {
            int d;
            scanf("%d",&d);
            //printf("ms[1]:%d\n",ms[1]);
            if(ms[1]<d) printf("0\n");
            else
            {
                 int p=query(d,1,n,1);
                 printf("%d\n",p);
                 updata(p,p+d-1,0,1,n,1);
            }
        }
        else if(op==2)
        {
            int x,d;
            scanf("%d%d",&x,&d);
            updata(x,x+d-1,1,1,n,1);
            //printf("ms[1]:%d\n",ms[1]);
        }
    }
    return 0;
}

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值