POJ 3667 hotel(shǎ崽大神的模板|区间合并)
继续线段树,这题其实是之前一次练习赛的题目,当时最后两小时苦憋这题。无奈一直TLE,只记得后来婷队讲解时还是一知半解,过了久了就忘记这题了。现在重新翻出来看看,是一道区间合并的题目。
英文一大堆,其实题意很简单:
输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边
输入 2 a b:将[a,a+b-1]的房间清空
思路:记录区间中最长的空房间
依然套用了大神的模板代码,真是好用啊。
因为是统计存在的最长连续房间,左右将值分成了三段,计算的时候分三个,即纯左孩子剩余间输中计算和纯右孩子剩余间输中计算,还有一左一右。就三种,有点lazy-tag的感觉,要记得update的时候碰到满足条件也要更新孩子节点。
#include <iostream> #include <stdio.h> #include <string.h> using namespace std; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 const int maxn=55555; int lsum[maxn<<2],rsum[maxn<<2],msum[maxn<<2]; //左右,总的剩余间输 int cover[maxn<<2]; //取值有 -1(初始),0 ,其他值 int max(int a,int b) //最大值函数 { return a>b?a:b; } void pushdown(int rt,int m) //更新儿子节点 { if(cover[rt]!=-1) { cover[rt<<1]=cover[rt<<1|1]=cover[rt]; msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=cover[rt]?0:m-(m>>1); msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=cover[rt]?0:(m>>1); cover[rt]=-1; } } void pushup(int rt,int m) //更新根节点 { lsum[rt]=lsum[rt<<1]; rsum[rt]=rsum[rt<<1|1]; if(lsum[rt]==m-(m>>1)) lsum[rt]+=lsum[rt<<1|1]; if(rsum[rt]==(m>>1)) rsum[rt]+=rsum[rt<<1]; msum[rt]=max(lsum[rt<<1|1]+rsum[rt<<1],max(msum[rt<<1],msum[rt<<1|1])); //根节点值 由下三段中最大值组成。纯左,纯右,一左一右 } void build(int l,int r,int rt) //建立 { msum[rt]=lsum[rt]=rsum[rt]=r-l+1; cover[rt]=-1; if(l==r) return ; int mid=(l+r)>>1; build(lson); build(rson); } void update(int L,int R,int c,int l,int r,int rt) //重要的是c的取值 0 还是非0 { if(L<=l&&r<=R) { msum[rt]=lsum[rt]=rsum[rt]=c?0:r-l+1; cover[rt]=c; return ; } pushdown(rt,r-l+1); int mid=(l+r)>>1; if(L<=mid) update(L,R,c,lson); if(mid<R) update(L,R,c,rson); pushup(rt,r-l+1); } int query(int w,int l,int r,int rt) { if(l==r) return l; pushdown(rt,r-l+1); //lazy-tag int mid=(l+r)>>1; if(msum[rt<<1]>=w) //纯左孩子 return query(w,lson); else if(rsum[rt<<1]+lsum[rt<<1|1]>=w) //一左一右 return mid-rsum[rt<<1]+1; return query(w,rson); //剩下纯右孩子 } int main() { int n,m; scanf("%d%d",&n,&m); build(1,n,1); while(m--) { int op,a,b; scanf("%d",&op); if(op==1) { scanf("%d",&a); if(msum[1]<a) puts("0"); else { int p=query(a,1,n,1); printf("%d\n",p); update(p,p+a-1,1,1,n,1); } } else { scanf("%d%d",&a,&b); update(a,a+b-1,0,1,n,1); } } return 0; }