【线段树区间合并】POJ3667-Hotel

【题意】

一段区间初始均为可行。有两个操作:

1→找出长度为w的一段可行区间,如果存在则返回这个可行区间最靠左的情况,并将该区间设为不可行;

2→将区间[a,b]设为可行区间。

【思路】

经典的线段树合并,代码依旧用的是神犇的线段树模板。详见注释。

【错误点】

延迟标记的时候,忘记把cover清为-1了,导致RE!

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cstdlib>
  6 using namespace std;
  7 #define lson l,m,rt<<1
  8 #define rson m+1,r,rt<<1|1
  9 const int MAXN=55555+10;
 10 int cover[MAXN<<2];//-1表示当前没有覆盖标记,1表示均覆盖为不可行,0表示均覆盖为可行
 11 int lsum[MAXN<<2];//该区间从左起连续的可用区间长度的最大值
 12 int msum[MAXN<<2];//该区间中连续的可用区间长度的最大值
 13 int rsum[MAXN<<2];//该区间从右起连续的可用区间长度的最大值
 14
 15 void PushUp(int rt,int m)
 16 {
 17     lsum[rt]=lsum[rt<<1];
 18     if (lsum[rt]==m-(m>>1)) lsum[rt]+=lsum[rt<<1|1];
 19     /*如果左孩子全部为可用区间,那么加上右孩子的左端*/
 20     rsum[rt]=rsum[rt<<1|1];
 21     if (rsum[rt]==m>>1) rsum[rt]+=rsum[rt<<1];
 22     /*同上*/
 23     msum[rt]=max(max(msum[rt<<1],msum[rt<<1|1]) , rsum[rt<<1]+lsum[rt<<1|1]);
 24     /*该区间的可用区间可能是:左孩子最大的可用区间、有孩子最大的可用区间,和跨越左右孩子加在一起的可用区间*/
 25 }
 26
 27 void PushDown(int rt,int m)
 28 {
 29     if (cover[rt]!=-1)
 30     {
 31         cover[rt<<1]=cover[rt<<1|1]=cover[rt];
 32         if (cover[rt]==1)
 33         {
 34             msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=0;
 35             msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=0;
 36         }
 37         else
 38         {
 39             msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=m-(m>>1);
 40             msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=m>>1;
 41         }
 42         cover[rt]=-1;
 43         /*千万不要忘记将rt清为-1*/
 44     }
 45 }
 46
 47
 48 int query(int w,int l,int r,int rt)
 49 {
 50     if (l==r) return l;
 51     PushDown(rt,r-l+1);
 52     int m=(l+r)>>1;
 53     if (msum[rt<<1]>=w) return(query(w,lson));
 54     /*由于要找最左边的区间,按照左孩子、跨越两者、有孩子的顺序查找*/
 55     if (rsum[rt<<1]+lsum[rt<<1|1]>=w) return(m-rsum[rt<<1]+1);
 56     return(query(w,rson));
 57 }
 58
 59 void update(int L,int R,int o,int l,int r,int rt)
 60 {
 61     if (L<=l && r<=R)
 62     {
 63         cover[rt]=o;
 64         if (o==1) msum[rt]=lsum[rt]=rsum[rt]=0;
 65             else msum[rt]=lsum[rt]=rsum[rt]=r-l+1;
 66         return;
 67     }
 68     PushDown(rt,r-l+1);//这里是l和r,不要写成L和R
 69     int m=(l+r)>>1;
 70     if (L<=m) update(L,R,o,lson);
 71     if (m<R)  update(L,R,o,rson);
 72     PushUp(rt,r-l+1);
 73 }
 74
 75 void build(int l,int r,int rt)
 76 {
 77     msum[rt]=lsum[rt]=rsum[rt]=r-l+1;
 78     cover[rt]=-1;
 79     if (l==r) return;
 80     int m=(l+r)>>1;
 81     build(lson);
 82     build(rson);
 83 }
 84
 85 int main()
 86 {
 87     int n,m;
 88     scanf("%d%d",&n,&m);
 89     build(1,n,1);
 90     for (int i=0;i<m;i++)
 91     {
 92         int op;
 93         scanf("%d",&op);
 94         if (op==1)
 95         {
 96             int w;
 97             scanf("%d",&w);
 98             if (msum[1]<w) cout<<0<<endl;
 99             /*如果根的可用区间已经小于w,那么一定是找不到长度为w的可用区间*/
100                 else
101                 {
102                       int p=query(w,1,n,1);
103                       cout<<p<<endl;
104                       update(p,p+w-1,1,1,n,1);
105                 }
106         }
107         else
108         {
109             int u,v;
110             scanf("%d%d",&u,&v);
111             update(u,u+v-1,0,1,n,1);
112         }
113     }
114     return 0;
115 }
时间: 2024-10-28 11:23:54

【线段树区间合并】POJ3667-Hotel的相关文章

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

Description The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Stree

POJ 3667 Hotel 【线段树 区间合并 + Lazy-tag】

Hotel Time Limit: 3000MS Memory Limit: 65536K 链接:POJ 3667   Description The cows are journeying north to ThunderBay in Canada to gain cultural enrichment and enjoy a vacation on the sunnyshores of Lake Superior. Bessie, ever the competent travel agen

Poj 3667——hotel——————【线段树区间合并】

Hotel Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 13124   Accepted: 5664 Description The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie

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

题目传送门 1 /* 2 题意:输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边 3 输入 2 a b:将[a,a+b-1]的房间清空 4 线段树(区间合并):lsum[]统计从左端点起最长连续空房间数,rsum[]类似,sum[]统计区间最长连续的空房间数, 5 它有三种情况:1.纯粹是左端点起的房间数:2.纯粹是右端点的房间数:3.当从左(右)房间起都连续时,加上另一个子节点 6 从左(右)房间起的数,sum[]再求最大值更新维护.理解没错,表达能力不足 7 详细解释:htt

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

Language: Default Hotel Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12417   Accepted: 5346 Description The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lak

poj3667 线段树 区间合并

1 //Accepted 3728 KB 1079 ms 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a document

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

题意: 有一个线段,从1到n,下面m个操作,操作分两个类型,以1开头的是查询操作,以2开头的是更新操作 1 w 表示在总区间内查询一个长度为w的可用区间并且要最靠左,能找到的话返回这个区间的左端点并占用了这个区间,找不到返回0 2 a len , 表示从单位a开始,清除一段长度为len的区间(将其变为可用,不被占用),不需要输出. 思路: 这是第一次遇到线段树区间合并的题目,写下感悟,还是对线段的更新和查询工作,但是查询的对象的性质已经不像单点那样,查询的是某个线段的最大可用区间是多少,还要一并

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

题目链接~~> 做题感悟:这题是接触线段树区间合并的第一题,做的很纠结. 解题思路: 注意线段树上节点代表的信息 : 每个节点需要维护 lc , rc , mc ,add ,见下图: add 为懒惰标记.假设 i 代表父亲节点编号,左儿子为  i * 2  ,右儿子为 i * 2  + 1 ,那么我们可以得到 : T [ i ] .lc 首先加上左儿子的左边的空格数,然后需要判断一下,如果左儿子的左节点占满了整个左区间时需要再加上右儿子的左边的空格数.同理 T [ i ] .rc 也可以这样得到

线段树 区间合并

poj3667 Hotel 区间合并入门题,照着代码打的, 题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边       2 a b:将[a,a+b-1]的房间清空思路:记录区间中最长的空房间,开三个数组,msum[rt]表示节点rt内连续的1的个数的最大值,lsum[rt]表示从节点rt左端点开始连续1的个数,rsum[rt]表示从节点rt右端点开始连续1的个数..线段树操作:update:区间替换 query:询问满足条件的最左端点 1 #include<iostream>

hdu4553约会安排(线段树区间合并)

链接 poj3667的加强版 当时的题解 这里只不过对于女神需要另开算,DS的占用的时间不加在女神身上,女神的时间都要加,清空的时候也都要算. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath>