2023牛客OI赛前集训营-提高组(第二场) 出租

文章描述了一个租房问题,通过线段树数据结构来处理租户的喜好位置和房间数量,以判断在满足特定条件下能否为每个租户分配理想房间。算法的时间复杂度为O(n+m)logn。

题目大意

你有nnn栋楼,编号为1∼n1\sim n1n,每栋楼都有kkk个房间可以出租,一个房间只能住一个人。每个人都有一个喜好位置xxx,表示他想要在x∼x+dx\sim x+dxx+d这些楼中住下。

现在有mmm次询问,每次询问给出两个数字x,yx,yx,y,表示来了yyy个喜好位置为xxx的租户想要租房。如果yyy为负数,则表示离开了−y-yy个喜好位置为xxx的租户。保证离开后喜好位置为xxx的租户不为负数。

对于每次询问,输出YESYESYESNONONO表示你能否染每个租户分配到理想的房间。

你可以随时更换租户的房间,但前提是新房间也要符合租户的喜好。

1≤n,m,d≤5×105,0≤k,y≤109,1≤x≤n−d1\leq n,m,d\leq 5\times 10^5,0\leq k,y\leq 10^9,1\leq x\leq n-d1n,m,d5×105,0k,y109,1xnd


题解

我们考虑什么时候输出NONONO

当存在一段区间[l,r][l,r][l,r],使得喜好位置(这里指xxx,不是x∼x+dx\sim x+dxx+d)在这段区间上的租户的人数大于k×(r−l+1+d)k\times (r-l+1+d)k×(rl+1+d)的时候,则无论如何都无法给这些租户安排理想的房间。

设喜好位置为iii的租户个数为viv_ivi,则有上文可得输出NONONO的条件为存在区间[l,r][l,r][l,r]使得∑i=lr(vi−k)>k×d\sum_{i=l}^r(v_i-k)>k\times di=lr(vik)>k×d

wiw_iwi表示喜好位置为iii的租户个数减去kkk之后的值,即vx−kv_x-kvxk,则输出NONONO的条件为存在区间[l,r][l,r][l,r]使得∑i=lrwi>k×d\sum_{i=l}^rw_i>k\times di=lrwi>k×d

用线段树维护wiw_iwi的最大子段和,每次操作只需进行单点修改并将[1,n][1,n][1,n]的最大子段和k×dk\times dk×d比较大小即可。

时间复杂度为O((n+m)log⁡n)O((n+m)\log n)O((n+m)logn)

code

#include<bits/stdc++.h>
#define lc k<<1
#define rc k<<1|1
using namespace std;
int n,m,K,d;
long long tr[4000005],wl[4000005],wr[4000005],mx[4000005];
void build(int k,int l,int r){
	if(l==r){
		tr[k]=-K;
		return;
	}
	int mid=l+r>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	tr[k]=tr[lc]+tr[rc];
}
void ch(int k,int l,int r,int x,int y){
	if(l==r&&l==x){
		tr[k]+=y;
		mx[k]=wl[k]=wr[k]=max(0ll,tr[k]);
		return;
	}
	int mid=l+r>>1;
	if(x<=mid) ch(lc,l,mid,x,y);
	else ch(rc,mid+1,r,x,y);
	wl[k]=max(wl[lc],tr[lc]+wl[rc]);
	wr[k]=max(wr[rc],tr[rc]+wr[lc]);
	mx[k]=max(wr[lc]+wl[rc],max(mx[lc],mx[rc]));
	tr[k]=tr[lc]+tr[rc];
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&K,&d);
	build(1,1,n);
	for(int i=1,x,y;i<=m;i++){
		scanf("%d%d",&x,&y);
		ch(1,1,n,x,y);
		if(mx[1]<=1ll*K*d) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值