ACM: Hotel 解题报告 - 线段树-区间合并
/**** 思路: 线段树的区间合并问题: 要查询连续区间长度,所以要记录最长的连续区间,一段区间的连续可以分为左连续,右连续,中间连续,然后记录就可以了 父节点左连续区间为左儿子左连续,如果左儿子在整个左区间内连续则再加上右儿子左连续 父节点右连续区间为右儿子右连续,如果右儿子在整个右区间内连续则再加上左儿子右连续 父节点中间连续区间为左儿子右连续加上右儿子左连续 然后记录每个节点总的最长连续区间的值 每次向上更新或者向下延迟都要重新计算节点信息 ****/
#include"iostream" #include"algorithm" #include"cstdio" #include"cstring" #include"cmath" //#define max(a,b) a>b?a:b //【这个地方WA了好多次。。。】 //#define min(a,b) a<b?a:b //【这个宏定义有问题。。。以后再也不随便用宏定义了。。。WA哭了。。。】 #define MX 110000 #define INF 0x3f3f3f3f #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; int lsum[MX<<2],rsum[MX<<2],sum[MX<<2]; int lazy[MX<<2]; // 1 a 询问是否存在a间连续的空房间,有则住进最左边 【】 // 2 a b 将 [a,a+b-1] 编号的房间清空 【成段更新】 void PushDown(int rt,int m) { if(lazy[rt]!=INF) {//1 -> lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt]; //下移懒惰标记 sum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=lazy[rt]*(m-(m>>1)); //因为 sum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=lazy[rt]*(m>>1); lazy[rt]=INF; } } 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]; // 这里lson[rt<<1]是表示的左区间的左最大值,lson[rt<<1|1]表示的是左区间的右最大值 if(rsum[rt]== (m>>1) ) rsum[rt]+=rsum[rt<<1]; // rson[。。。] 类似 而左区间的右最大值加右区间的左最大值就是中间区间的最大值 sum[rt]=max(max(sum[rt<<1],sum[rt<<1|1]),lsum[rt<<1|1]+rsum[rt<<1]); //保存两边子节点和 中最大值 中的最大值 } void Build(int l,int r,int rt) { sum[rt]=lsum[rt]=rsum[rt]=r-l+1; //把每一个空房间标记为1,每个父节点记录为子节点最大的空区间 lazy[rt]=INF; //懒惰标记清空 if(l==r) return ; int m=(r+l)>>1; Build(lson); Build(rson); } void UpData(int L,int R,int val,int l,int r,int rt) { if(L<=l&&r<=R) { sum[rt]=lsum[rt]=rsum[rt]= val ? (r-l+1):0; lazy[rt]=val; return ; } PushDown(rt,r-l+1); int m=(r+l)>>1; if(L<=m) UpData(L,R,val,lson); if(R> m) UpData(L,R,val,rson); PushUp(rt,r-l+1); } int Query(int ll,int l,int r,int rt) { if(l==r) return l; PushDown(rt,r-l+1); int m=(r+l)>>1; if(sum[rt<<1]>=ll) return Query(ll,lson); //如果左最大值满足就在往左继续搜 else if(rsum[rt<<1]+lsum[rt<<1|1]>=ll)return m-rsum[rt<<1]+1;//如果中最大值,满足就输出左区间的右最大值的第一个位置 return Query(ll,rson); //否则就向右继续搜 } int main() { int n,m; scanf("%d%d",&n,&m); Build(1,n,1); int o,a,b; for(int i=0; i<m; i++) { scanf("%d",&o) ; if(o==1) { scanf("%d",&a); if(sum[1]<a) printf("0\n"); else { int q=Query(a,1,n,1); printf("%d\n",q); UpData(q,q+a-1,0,1,n,1); } } else if(o==2) { scanf("%d%d",&a,&b); UpData(a,a+b-1,1,1,n,1); } } return 0; }