码迷,mamicode.com
首页 > 其他好文 > 详细

[USACO08FEB] 酒店Hotel - 线段树

时间:2020-02-10 10:16:48      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:query   开始   线段   区间   c++   lse   --   clu   scan   

第一行输入n,m ,n代表有n个房间,编号为1---n,开始都为空房,m表示以下有m行操作,以下 每行先输入一个数 i ,表示一种操作:

若i为1,表示查询房间,再输入一个数x,表示在1--n 房间中找到长度为x的连续空房,输出连续x个房间中左端的房间号,尽量让这个房间号最小,若找不到长度为x的连续空房,输出0,并且在这x个空房间中住上人。

若i为2,表示退房,再输入两个数 x,y 代表 房间号 x---x+y-1 退房,即让房间为空。

Solution

显然用线段树维护,用类似最大子段和的方法处理

考虑 update,无非就是更新单侧值,然后再讨论三种情况更新一下 ans

比较揪心的是如何查询,我们考虑如何在查询时讨论

  • 如果到达递归边界就表明找到,返回

  • 如果左区间足够多就去左区间

  • 否则,如果中间足够多,就直接返回左区间从右开始的最长连续的左端点

  • 否则去右区间找

#include <bits/stdc++.h>
using namespace std;

const int N = 2000005;

int ml[N],mr[N],mx[N],len[N],tag[N];

void build(int p,int l,int r) {
    ml[p]=mr[p]=mx[p]=len[p]=r-l+1;
    if(l<r) {
        build(p*2,l,(l+r)/2);
        build(p*2+1,(l+r)/2+1,r);
    }
}

void update(int p) {
    if(len[p]==1) return;
    if(mx[p*2]==len[p*2]) ml[p]=len[p*2]+ml[p*2+1];
    else ml[p]=ml[p*2];
    if(mx[p*2+1]==len[p*2+1]) mr[p]=len[p*2+1]+mr[p*2];
    else mr[p]=mr[p*2+1];
    mx[p]=max(max(mx[p*2],mx[p*2+1]),mr[p*2]+ml[p*2+1]);
}

void pushdown(int p) {
    if(tag[p]==0) return;
    if(tag[p]==1) {
        ml[p*2]=mr[p*2]=mx[p*2]=len[p*2];
        ml[p*2+1]=mr[p*2+1]=mx[p*2+1]=len[p*2+1];
    }
    if(tag[p]==-1) {
        ml[p*2]=mr[p*2]=mx[p*2]=0;
        ml[p*2+1]=mr[p*2+1]=mx[p*2+1]=0;
    }
    tag[p*2]=tag[p*2+1]=tag[p];
    tag[p]=0;
}

void modify(int p,int l,int r,int ql,int qr,int c) {
    if(l>qr || r<ql) return;
    if(l>=ql&&r<=qr) {
        if(c) ml[p]=mr[p]=mx[p]=len[p], tag[p]=1;
        else ml[p]=mr[p]=mx[p]=0, tag[p]=-1;
    }
    else {
        pushdown(p);
        modify(p*2,l,(l+r)/2,ql,qr,c);
        modify(p*2+1,(l+r)/2+1,r,ql,qr,c);
        update(p);
    }
}

int query(int p,int l,int r,int ql,int qr,int k) {
    if(l==r) return l;
    pushdown(p);
    if(mx[p*2]>=k) return query(p*2,l,(l+r)/2,ql,qr,k);
    if(mr[p*2]+ml[p*2+1]>=k) return (l+r)/2-mr[p*2]+1;
    return query(p*2+1,(l+r)/2+1,r,ql,qr,k);
}

int n,m,t1,t2,t3;

int main() {
    scanf("%d%d",&n,&m);
    build(1,1,n);
    for(int i=1;i<=m;i++) {
        scanf("%d",&t1);
        if(t1==1) {
            scanf("%d",&t2);
            if(mx[1]>=t2) {
                t3=query(1,1,n,1,n,t2);
                printf("%d\n",t3);
                modify(1,1,n,t3,t3+t2-1,0);
            }
            else printf("0\n");
        }
        else {
            scanf("%d%d",&t2,&t3);
            modify(1,1,n,t2,t2+t3-1,1);
        }
    }
}

[USACO08FEB] 酒店Hotel - 线段树

标签:query   开始   线段   区间   c++   lse   --   clu   scan   

原文地址:https://www.cnblogs.com/mollnn/p/12289796.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!