poj 3667Hotel(经典线段树)

传送门:点击打开链接

题目大意:

有N个房间排在一列,有两种操作。

1:查询最靠左的长度为len的空房间,并且入住这些空房间。

2:以l开头,长度为r的房间退房。(如果本来就是空的 还是要退房)。

解题思路:

一类经典的线段树题目。区间合并类。

容易想到在查询上做做手脚,这题就差不多了。问题在于维护哪些东西。由于两个子区间要求合并,那么可以记录一个前最长可用连续,后最长可用连续,和连续可用的最大值。

那么pushup函数和pushdown函数就很简单了。

下面就是查询:如果左区间的连续值是大于等于要求的话,那么查左区间,如果右区间的连续值大于等于要求的话 ,查询右区间。

如果左区间的右连续+右区间的左连续大于等于要求的话。可以直接返回区间的最左下标。

注意:因为要求最偏左,所以注意顺序。

学了几天线段树了,感觉还是没怎么入门。慢慢来吧。

#include <cstdio>
#include <algorithm>
#define maxn 50010
using namespace std;
struct Node
{
    int l,r;
    int sum,pre,suf;//最长可用区间,左最长,右最长
    int c;//0表示未被占用 ,1表示被占用
}tree[maxn<<2];

inline void pushup(int id)
{
    if(tree[id<<1].sum == tree[id<<1].r-tree[id<<1].l+1)
        tree[id].pre = tree[id<<1].sum + tree[id<<1|1].pre;
    else
        tree[id].pre = tree[id<<1].pre;

    if(tree[id<<1|1].sum == tree[id<<1|1].r-tree[id<<1|1].l+1)
        tree[id].suf = tree[id<<1|1].sum + tree[id<<1].suf;
    else
        tree[id].suf = tree[id<<1|1].suf;

    tree[id].sum = max(max(tree[id<<1].sum,tree[id<<1|1].sum),tree[id<<1].suf+tree[id<<1|1].pre);
}

inline void pushdown(int id)
{
    if(tree[id].c+1)
    {
        tree[id<<1].c = tree[id<<1|1].c = tree[id].c;
        int len = (tree[id].r- tree[id].l + 1);
        int len1 = len-(len>>1);
        int len2 = len>>1;
        if(tree[id].c)//标记是1,全部标记为不可用
        {
            tree[id<<1].pre = 0;
            tree[id<<1].suf = 0;
            tree[id<<1].sum = 0;
            tree[id<<1|1].sum = 0;
            tree[id<<1|1].pre = 0;
            tree[id<<1|1].suf = 0;
        }
        else//标记是0,表示全部都可用
        {
            tree[id<<1].pre = len1;
            tree[id<<1].suf = len1;
            tree[id<<1].sum = len1;
            tree[id<<1|1].sum = len2;
            tree[id<<1|1].pre = len2;
            tree[id<<1|1].suf = len2;
        }
        tree[id].c = -1;
    }
}

void build(int id,int l,int r)
{
    tree[id].l = l;
    tree[id].r = r;
    tree[id].c = -1;
    if(l == r)
    {
        tree[id].sum = 1;
        tree[id].suf = 1;
        tree[id].pre = 1;
        return ;
    }
    int mid = (l+r)>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    pushup(id);
}

void op(int id,int l,int r,int c)
{
    if(tree[id].l >= l &&tree[id].r <= r)
    {
        if(c)
            tree[id].pre = tree[id].suf = tree[id].sum = 0;
        else
            tree[id].pre = tree[id].suf = tree[id].sum = tree[id].r-tree[id].l+1;
        tree[id].c = c;
        return ;
    }
    pushdown(id);
    int mid = (tree[id].l + tree[id].r) >>1;
    if(l <= mid ) op(id<<1,l,r,c);
    if(mid < r) op(id<<1|1,l,r,c);
    pushup(id);
}

int query(int id,int len)
{
    if(tree[id].l == tree[id].r) return tree[id].l;
    pushdown(id);
    int mid = (tree[id].l + tree[id].r)>>1;
    if(tree[id<<1].sum >= len)
        return query(id<<1,len);
    else if(tree[id<<1].suf + tree[id<<1|1].pre >= len)
        return mid - tree[id<<1].suf+1;
    else
        return query(id<<1|1,len);
}

int main()
{
    int n,q;
    while(scanf("%d %d",&n,&q) != EOF)
    {
        build(1,1,n);
        while(q--)
        {
            int ch;
            scanf("%d",&ch);
            if(ch == 1)
            {
                int len;
                scanf("%d",&len);
                if(tree[1].sum < len)
                {
                    printf("0\n");
                    continue;
                }
                int pos= query(1,len);
                printf("%d\n",pos);
                op(1,pos,pos+len-1,1);
            }
            else
            {
                int l,r;
                scanf("%d %d\n",&l,&r);
                op(1,l,l+r-1,0);
            }
        }
    }
    return 0;
}
时间: 2024-08-27 17:03:32

poj 3667Hotel(经典线段树)的相关文章

POJ 2481 Cows (线段树)

Cows 题目:http://poj.org/problem?id=2481 题意:有N头牛,每只牛有一个值[S,E],如果对于牛i和牛j来说,它们的值满足下面的条件则证明牛i比牛j强壮:Si <=Sjand Ej <= Ei and Ei - Si > Ej - Sj.现在已知每一头牛的测验值,要求输出每头牛有几头牛比其强壮. 思路:将牛按照S从小到大排序,S相同按照E从大到小排序,这就保证了排在后面的牛一定不比前面的牛强壮.再按照E值(离散化后)建立一颗线段树(这里最值只有1e5,所

POJ 2299 离散化线段树

点击打开链接 Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 40827   Accepted: 14752 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by

POJ训练计划2299_Ultra-QuickSort(线段树/单点更新)

解题报告 题意: 求逆序数. 思路: 线段树离散化处理. #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define LL long long using namespace std; LL sum[2001000],num[501000],_hash[501000]; void push_up(int rt) { sum[rt]=sum[rt*2

POJ 3667(线段树区间合并)

http://poj.org/problem?id=3667 题意:两个操作 : 1 选出靠左的长度为a的区间. 2 把从 a到a+b的区间清空. 线段树区间合并+lazy // by caonima // hehe #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cmath> using namespace std; co

ZOJ1610 Count the Colors 经典线段树染色问题

题意,给你n个  x,y,c,意思就是区间[x,y]被染成C色,但是颜色会被覆盖的,染色操作完成以后 问你每种颜色有多少段 并输出颜色编号id跟段数cnt 经典问题,不过写的有点撮吧,没去看别人的,这个方法应该是最传统的最普通的,常规的开数组记录,也许大神们有更高端的方法 #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring>

POJ&#183;1151 Atlantis&#183;线段树求矩形面积并

题目在这:http://poj.org/problem?id=1151 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the is

POJ 2299 Ultra-QuickSort(线段树+离散化)

题目地址:POJ 2299 这题曾经用归并排序做过,线段树加上离散化也可以做.一般线段树的话会超时. 这题的数字最大到10^10次方,显然太大,但是可以利用下标,下标总共只有50w.可以从数字大的开始向树上加点,然后统计下标比它小即在它左边的数的个数.因为每加一个数的时候,比该数大的数已经加完了,这时候坐标在它左边的就是一对逆序数. 但是该题还有一个问题,就是数字重复的问题.这时候可以在排序的时候让下标大的在前面,这样就可以保证加点的时候下标比他小的数中不会出现重复的. 这题需要注意的是要用__

poj 2777(线段树的节点更新策略)

1 /* 2 之前的思想是用回溯的方式进行颜色的更新的!如果用回溯的方法的话,就是将每一个节点的颜色都要更新 3 通过子节点的颜色情况来判断父节点的颜色情况 !这就是TLE的原因! 4 5 后来想一想没有必要 !加入[a, b] 区间有p管辖,那么tree[p]的颜色值就是[a, b]所有点的颜色值! 6 如果[a,b]的子区间[c,d]没被跟新,那么tree[p]也是[c,d]的值! 7 否则,在更新[c,d]区间的时候,一定会经过 p 点!然后由上到下更新p<<1 和 p<<1

poj 3468(简单线段树区间更新)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 61936   Accepted: 18934 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of