旅馆Hotel 题解

定义
计 0 为空房间,1 为有人的房间,[lx,rx]为当前线段树区间

定义线段树记录一下内容——

1. k0,[lx,rx]中连续最大空房间数量
2. l0,[lx,rx]中从左往右连续的空房间数量
3. r0,[lx,rx]中从右往左连续的空房间数量


pushup(int x)


pushup 时按照以下方式合并

对于K0——

1. 可以是lson.k0,

2. 也可以是rson.k0,

3. 还可能是lson.r0+rson.l0。

对于L0——

1. L0=lson.l0

2. 若lson.l0=lson.len,则L0=lson.len+rson.l0

对于R0——

1. R0=rson.r0

2. 若rson.r0=rson.len,则R0=rson.llen+lson.r0


pushdown


定义 tag 为线段树节点的 lazy_tag
1. tag=-1 时,不下传
2. tag!=-1 时,表示是下传全空还是全满
3.

   void pushdown(int x){
    if(tree[x].tag==-1)return;
    if(tree[x].tag){
        tree[ls(x)].k0=tree[ls(x)].l0=tree[ls(x)].r0=0;
        tree[rs(x)].k0=tree[rs(x)].l0=tree[rs(x)].r0=0;
        tree[ls(x)].tag=tree[rs(x)].tag=1;
    }
    else{
        tree[ls(x)].k0=tree[ls(x)].l0=tree[ls(x)].r0=(tree[ls(x)].r-tree[ls(x)].l+1);
        tree[rs(x)].k0=tree[rs(x)].l0=tree[rs(x)].r0=(tree[rs(x)].r-tree[rs(x)].l+1);
        tree[ls(x)].tag=tree[rs(x)].tag=0;
    }
    tree[x].tag=-1;
    return;
}


query

权值线段树的思想走

int query(int x,int len){
    if(tree[x].k0<len)return 0;
    if(tree[x].l==tree[x].r)return tree[x].l;
    pushdown(x);
    if(tree[ls(x)].k0>=len)return query(ls(x),len);
    if(tree[ls(x)].r0+tree[rs(x)].l0>=len)return tree[ls(x)].r-tree[ls(x)].r0+1;
    return query(rs(x),len);
}

Code

#include<bits/stdc++.h>
#define ls(x) ((x)<<1)
#define rs(x) ((x)<<1|1)
using namespace std;
const int MAXN=50000;
int n,m;
struct Node{
	int k0,l0,r0,l,r,tag;
}tree[MAXN*4+1];
void pushup(int x){
	int mid=tree[x].l+tree[x].r;mid>>=1;
	tree[x].k0=max({tree[ls(x)].k0,tree[rs(x)].k0,tree[ls(x)].r0+tree[rs(x)].l0});
	tree[x].l0=max(tree[ls(x)].l0,(tree[ls(x)].l0+tree[rs(x)].l0)*(mid-tree[x].l+1==tree[ls(x)].l0));
	tree[x].r0=max(tree[rs(x)].r0,(tree[rs(x)].r0+tree[ls(x)].r0)*(tree[x].r-mid==tree[rs(x)].r0));
	return;
}
void pushdown(int x){
	if(tree[x].tag==-1)return;
	if(tree[x].tag){
		tree[ls(x)].k0=tree[ls(x)].l0=tree[ls(x)].r0=0;
		tree[rs(x)].k0=tree[rs(x)].l0=tree[rs(x)].r0=0;
		tree[ls(x)].tag=tree[rs(x)].tag=1;
	}
	else{
		tree[ls(x)].k0=tree[ls(x)].l0=tree[ls(x)].r0=(tree[ls(x)].r-tree[ls(x)].l+1);
		tree[rs(x)].k0=tree[rs(x)].l0=tree[rs(x)].r0=(tree[rs(x)].r-tree[rs(x)].l+1);
		tree[ls(x)].tag=tree[rs(x)].tag=0;
	}
	tree[x].tag=-1;
	return;
}
void build(int x,int lx,int rx){
	tree[x].l=lx,tree[x].r=rx;tree[x].tag=-1;
	if(lx==rx){
		tree[x].k0=tree[x].l0=tree[x].r0=1;
		return;
	}
	build(ls(x),lx,(lx+rx)/2);
	build(rs(x),(lx+rx)/2+1,rx);
	pushup(x);
	return;
}
void change(int x,int L,int R,int d){
	if(L<=tree[x].l&&tree[x].r<=R){
		tree[x].tag=d;
		tree[x].k0=tree[x].l0=tree[x].r0=(d?0:(tree[x].r-tree[x].l+1));
		return;
	}
	pushdown(x);
	int mid=(tree[x].l+tree[x].r)>>1;
	if(L<=mid)change(ls(x),L,R,d);
	if(R>mid)change(rs(x),L,R,d);
	pushup(x);
	return;
}
int query(int x,int len){
	if(tree[x].k0<len)return 0;
	if(tree[x].l==tree[x].r)return tree[x].l;
	pushdown(x);
	if(tree[ls(x)].k0>=len)return query(ls(x),len);
	if(tree[ls(x)].r0+tree[rs(x)].l0>=len)return tree[ls(x)].r-tree[ls(x)].r0+1;
	return query(rs(x),len);
}
int main(){
	scanf("%d%d",&n,&m);
	build(1,1,n);
	while(m--){
		int op;scanf("%d",&op);
		if(op==2){
			int x,d;scanf("%d%d",&x,&d);
			change(1,x,x+d-1,0);
		}
		else{
			int d;scanf("%d",&d);
			int ans=query(1,d);
			printf("%d\n",ans);
			if(!ans)continue;
			change(1,ans,ans+d-1,1);
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值