题意:一个hotel,有n个连续的房间,开始时均无人住宿
共有3种操作
1 a b 从a开始连续b个房间全部旅客住宿 [a,a+b-1];
2 a b 从a开始连续b个房间全部旅客离开 [a,a+b-1];
3 查询最长连续空房间
思路:线段树,记录每个节点,左边,右边各最多连续空房间lmax,rmax; 以及这个区间内最多空房间max
#include<iostream>
#include<cmath> using namespace std; #define MAXN 16001 struct node { int lmax,rmax,max; int left,right; int flag;//0:全空;1:全部被占用;2:部分被占用 }; node tree[MAXN*4]; void build(int i) { tree[i].lmax=tree[i].rmax=tree[i].max=tree[i].right-tree[i].left+1;//当前节点的max,lmax和rmax都初始化为right-left+1 tree[i].flag=0; if(tree[i].left==tree[i].right) return ; int mid=(tree[i].left+tree[i].right)/2; tree[2*i].left=tree[i].left; tree[2*i].right=mid; tree[2*i+1].left=mid+1; tree[2*i+1].right=tree[i].right; build(2*i); build(2*i+1); } void insert(int i,int x,int y,int c) { //cout<<i<<" "<<x<<" "<<y<<" "<<c<<" "<<tree[i].left<<" "<<tree[i].right<<endl; if(tree[i].left==x&&tree[i].right==y) { tree[i].flag=c; if(c==1) tree[i].lmax=tree[i].rmax=tree[i].max=0; else tree[i].lmax=tree[i].rmax=tree[i].max=tree[i].right-tree[i].left+1; return; }//当前节点完全递归返回前未被占用,保证“当前节点的子节点的状态被标记为0”优先级最高
//具体解析:因为之前操作中的插入或者删除操作都是到达满足if(tree[i].left==x&&tree[i].right==y)的条件之后就返回了,
//但是我们之后要进行的插入和删除操作要是区段有可能比之前涉及到的区段小,这个时候在递归之前判断当前节点状态并且
//对相应左子树和右子树执行更新操作就很有必要了
if(tree[i].flag==0) { tree[2*i].flag=tree[2*i+1].flag=0;//左右子树的各个最长子段都设为right-left+1
tree[2*i].lmax=tree[2*i].rmax=tree[2*i].max=tree[2*i].right-tree[2*i].left+1; tree[2*i+1].lmax=tree[2*i+1].rmax=tree[2*i+1].max=tree[2*i+1].right-tree[2*i+1].left+1; }//当前节点递归返回前完全被占用,保证“当前节点的子节点的状态被标记为1”优先级最高(具体解析同上)
if(tree[i].flag==1) { tree[2*i].flag=tree[2*i+1].flag=1; //左右子树的各个最长子段都设为0 tree[2*i].lmax=tree[2*i].rmax=tree[2*i].max=0; tree[2*i+1].lmax=tree[2*i+1].rmax=tree[2*i+1].max=0; } //递归操作 int mid=(tree[i].left+tree[i].right)/2; if(y<=mid) insert(2*i,x,y,c); else if(x>mid) insert(2*i+1,x,y,c); else { insert(2*i,x,mid,c); insert(2*i+1,mid+1,y,c); } //延迟处理,更新当前节点的状态 if(tree[2*i].flag==0&&tree[2*i+1].flag==0)//左右子树均全空 { tree[i].flag=0; tree[i].lmax=tree[i].rmax=tree[i].max=tree[i].right-tree[i].left+1; } else if(tree[2*i].flag==0&&tree[2*i+1].flag==1)//左子树全空,右子树全被占用 { tree[i].flag=2; tree[i].lmax=tree[i].max=tree[2*i].max; tree[i].rmax=0; } else if(tree[2*i].flag==1&&tree[2*i+1].flag==0)//左子树被占用,右子树全空 { tree[i].flag=2; tree[i].rmax=tree[i].max=tree[2*i+1].max; tree[i].lmax=0; } else if(tree[2*i].flag==1&&tree[2*i+1].flag==1)//左右子树都全被占用 { tree[i].flag=1; tree[i].lmax=tree[i].rmax=tree[i].max=0; } else//左子树或者右子树含有部分被占用的情况 { tree[i].flag=2; tree[i].max=max(tree[2*i].max,tree[2*i+1].max); tree[i].max=max(tree[i].max,tree[2*i].rmax+tree[2*i+1].lmax); if(tree[2*i].flag==0)tree[i].lmax=tree[2*i].max+tree[2*i+1].lmax;
elsetree[i].lmax=tree[2*i].lmax;
if(tree[2*i+1].flag==0)tree[i].rmax=tree[2*i].rmax+tree[2*i+1].max;
elsetree[i].rmax=tree[2*i+1].rmax;
} } int main() { int n,m; scanf("%d%d",&n,&m); tree[1].left=1; tree[1].right=n; build(1); int i; int x,y,c; for(i=1;i<=m;i++) { scanf("%d",&c); if(c==3) printf("%d\n",tree[1].max); if(c==1) { scanf("%d%d",&x,&y); insert(1,x,x+y-1,1); } if(c==2) { scanf("%d%d",&x,&y); insert(1,x,x+y-1,0); } } return 0; }