题意:旅馆有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; }