题意:旅馆有n个房间,初始都是空的,有p次操作,操作1是占用房间a~a+b-1,操作2是清空房间a~a+b-1,操作3是询问最大连续空房数。
思路:线段树(区间更新)。每个节点维护3个值,空前缀长度,空后缀长度,最大连续空房数。区间合并时就根据它们合并起来。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
#define maxn 16010
struct node{
int l,r;
int sub,pre,suf;
bool lazy;
};
node tree[maxn<<2];
void push_down(int n){
tree[n].lazy=0;
tree[n*2].lazy=tree[n*2+1].lazy=1;
if(tree[n].sub){
tree[n*2].sub=tree[n*2].pre=tree[n*2].suf= tree[n*2].r-tree[n*2].l+1;
tree[n*2+1].sub=tree[n*2+1].pre=tree[n*2+1].suf= tree[n*2+1].r-tree[n*2+1].l+1;
}else{
tree[n*2].sub=tree[n*2].pre=tree[n*2].suf= 0;
tree[n*2+1].sub=tree[n*2+1].pre=tree[n*2+1].suf= 0;
}
}
void push_up(node& p,node& lch,node& rch){
p.sub=max(lch.suf+rch.pre, max(lch.sub,rch.sub) );
if(lch.sub==lch.r-lch.l+1){
p.pre=lch.sub+rch.pre;
}else{
p.pre=lch.pre;
}
if(rch.sub==rch.r-rch.l+1){
p.suf=rch.sub+lch.suf;
}else{
p.suf=rch.suf;
}
}
void build_tree(int n,int l,int r){
tree[n].l=l; tree[n].r=r;
tree[n].sub=tree[n].pre=tree[n].suf=r-l+1;
tree[n].lazy=0;
if(l==r){
return;
}
int mid=(l+r)>>1;
build_tree(n*2,l,mid);
build_tree(n*2+1,mid+1,r);
}
void update(int n,int l,int r,bool f){
if(tree[n].l==l&&tree[n].r==r){
tree[n].lazy=1;
if(f){
tree[n].pre=tree[n].suf=tree[n].sub=0;
}else{
tree[n].pre=tree[n].suf=tree[n].sub=r-l+1;
}
return;
}
if(tree[n].lazy)push_down(n);
int mid=(tree[n].l+tree[n].r)>>1;
if(r<=mid){
update(n*2,l,r,f);
}else{
if(l>mid){
update(n*2+1,l,r,f);
}else{
update(n*2,l,mid,f);
update(n*2+1,mid+1,r,f);
}
}
push_up(tree[n],tree[n*2],tree[n*2+1]);
}
int main(){
int n,p;
while(cin>>n>>p){
build_tree(1,1,n);
for(int i=1;i<=p;i++){
int op;
scanf("%d",&op);
if(op==1){
int a,b;
scanf("%d%d",&a,&b);
b=a+b-1;
update(1,a,b,1);
}else if(op==2){
int a,b;
scanf("%d%d",&a,&b);
b=a+b-1;
update(1,a,b,0);
}else{
printf("%d\n",tree[1].sub);
}
}
}
return 0;
}
本文介绍了一种利用线段树解决旅馆房间占用与查询问题的方法。通过维护每个节点的空前缀长度、空后缀长度及最大连续空房数,实现了区间更新与查询最大连续空闲区间的功能。
686

被折叠的 条评论
为什么被折叠?



