poj3667 Hotel (线段树区间合并)

来源:互联网 发布:access2003数据库 编辑:程序博客网 时间:2024/03/19 13:07

链接:http://poj.org/problem?id=3667

题意:n个连续的房间m个操作。操作分两种,第一种以1 x形式给出,找到最左的能连续容下x个人的连续房间,并输出左端点的编号,如果找不到就输出0.第二种以2 l x的形式给出,表示以l为起点的x个房间都清空。


查询的时候要能直接获取区间的最大连续空房间,这样就能判断能不能连续放下这x个人,但这样还确定不了具体放哪。放的位置有三种情况1.放在左儿子那个区间。2.放在右儿子那个区间。3.放在左右儿子中间,就是占用左区间的右部分和右区间的左部分。

这样就需要用sum保存整个区间最大的连续段,lsum保存从左端开始的最大连续段,rsum保存右端开始的最大连续段

用一个标记mark表示区间状态,0:区间全空。1:区间全满。-1:当前区间已初始化,不用向下更新


向下更新策略:先向下转移标记mark,在通过标记更新相应的数据。

向上更新策略:sum=max(左儿子的sum,右儿子的sum,左右儿子中间部分)

lsum=左儿子的lsum,如果左儿子为空还要加上右儿子的lsum

rsum=右儿子的rsum,如果右儿子为空还要加上左儿子的rsum


#include<stdio.h>#include<string.h>#define MAXN 50005struct node{int l,r;int mark;int lsum,rsum,sum;int getlen() {return r-l+1;}void getsum() {lsum=rsum=sum=(mark?0:getlen());}}t[MAXN*4];int max(int a,int b) {return a>b?a:b;}void construct(int l,int r,int p){t[p].l=l,t[p].r=r;t[p].lsum=t[p].rsum=t[p].sum=t[p].getlen();t[p].mark=-1;if(l==r) return ;int m=(l+r)>>1;construct(l,m,p*2);construct(m+1,r,p*2+1);}int query(int x,int p){if(t[p].l==t[p].r&&x==1) return t[p].l;//单个节点特判if(t[p].mark!=-1){t[p*2].mark=t[p*2+1].mark=t[p].mark;t[p].mark=-1;t[p*2].getsum();t[p*2+1].getsum();}if(x<=t[p*2].sum) return query(x,p*2);else if(t[p*2].rsum+t[p*2+1].lsum>=x) return t[p*2].r-t[p*2].rsum+1;else if(x<=t[p*2+1].sum) return query(x,p*2+1);else return 0;}void modify(int l,int r,int val,int p){if(t[p].l==l&&t[p].r==r){t[p].mark=val;t[p].getsum();return ;}if(t[p].mark!=-1){t[p*2].mark=t[p*2+1].mark=t[p].mark;t[p].mark=-1;//每次更新了mark标记都要重新获取长度t[p*2].getsum();t[p*2+1].getsum();}int m=(t[p].l+t[p].r)>>1;if(r<=m) modify(l,r,val,p*2);else if(l>m) modify(l,r,val,p*2+1);else {modify(l,m,val,p*2);modify(m+1,r,val,p*2+1);}int temp=max(t[p*2].sum,t[p*2+1].sum);t[p].sum=max(temp,t[p*2].rsum+t[p*2+1].lsum);t[p].lsum=t[p*2].lsum;t[p].rsum=t[p*2+1].rsum;if(t[p*2].sum==t[p*2].getlen()) t[p].lsum+=t[p*2+1].lsum;if(t[p*2+1].sum==t[p*2+1].getlen()) t[p].rsum+=t[p*2].rsum;}int main(){int op,l,x,n,m;while(scanf("%d%d",&n,&m)!=EOF){construct(1,n,1);while(m--){scanf("%d",&op);if(op==1){scanf("%d",&x);int flag=query(x,1);printf("%d\n",flag);if(flag) modify(flag,flag+x-1,1,1);}else{scanf("%d%d",&l,&x);modify(l,l+x-1,0,1);}}}return 0;}