洛谷——P4198 楼房重建

题目描述

小 A 的楼房外有一大片施工工地,工地上有 NN 栋待建的楼房。每天,这片工地上的房子拆了又建、建了又拆。他经常无聊地看着窗外发呆,数自己能够看到多少栋房子。

为了简化问题,我们考虑这些事件发生在一个二维平面上。小 A 在平面上 (0,0)(0,0) 点的位置,第 ii 栋楼房可以用一条连接 (i,0)(i,0) 和 (i,H_i)(i,H
i

) 的线段表示,其中 H_iH
i

为第 ii 栋楼房的高度。如果这栋楼房上任何一个高度大于 00 的点与 (0,0)(0,0) 的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。

施工队的建造总共进行了 MM 天。初始时,所有楼房都还没有开始建造,它们的高度均为 00。在第 ii 天,建筑队将会将横坐标为 X_iX
i

的房屋的高度变为 Y_iY
i

(高度可以比原来大—修建,也可以比原来小—拆除,甚至可以保持不变—建筑队这天什么事也没做)。请你帮小 A 数数每天在建筑队完工之后,他能看到多少栋楼房?

输入格式

第一行两个正整数 N,MN,M。

接下来 MM 行,每行两个正整数 X_i,Y_iX
i

,Y
i

输出格式

MM 行,第 ii 行一个整数表示第 ii 天过后小 A 能看到的楼房有多少栋。

输入输出样例

输入 #1复制
3 4
2 4
3 6
1 1000000000
1 1
输出 #1复制
1
1
1
2

说明/提示

对于 100%100% 的数据,1 \le X_i \le N1≤X
i

≤N,1 \le Y_i \le 10^91≤Y
i

≤10
9
,1\le N,M \le 10^51≤N,M≤10
5

区间查询+修改,线段树没跑了
要看到后面的楼,考虑斜率就好了,后面的楼的斜率只要大于当前楼的斜率,就可以看到了。所以求一个最长递增斜率就可以了。
具体解释看代码吧。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+500;
struct tree {
	int l,r;
	double k;
	int ans;
#define l(p) t[p].l
#define r(p) t[p].r
#define k(p) t[p].k
#define ans(p) t[p].ans
} t[N*4];
void build(int p,int l,int r) {
	l(p)=l,r(p)=r,ans(p)=0,k(p)=0;
	if(l==r)return;
	int mid=(l+r)/2;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
}
int ask(int p,double maxx) {
	//当前区间没有大于maxx的,所以返回0 
	if(k(p)<=maxx)return 0;
	//处理最底层,大于返回1,小于返回0 
	if(l(p)==r(p)) {
		return k(p)>maxx;
	} else if(k(p*2)<=maxx) {
	//如果左子树全部小于,则取右子树 
		return ask(p*2+1,maxx);
	}//整个区间的答案减去左区间的答案,然后重新查询左区间 
	return ask(p*2,maxx)+ans(p)-ans(p*2);
}
void change(int p,int x,double val) {
	if(l(p)==r(p)) {
		ans(p)=1,k(p)=val;
		return;
	}
	int mid=(l(p)+r(p))/2;
	if(x<=mid) {
		change(p*2,x,val);
	} else {
		change(p*2+1,x,val);
	}
	//取区间最大值 
	k(p)=max(k(p*2),k(p*2+1));
	//区间答案等于左区间答案加上右区间比左区间答案大的答案 
	ans(p)=ans(p*2)+ask(p*2+1,k(p*2));
}
int main() {
	int n,m;
	scanf("%d %d",&n,&m);
	build(1,1,n);
	while(m--) {
		int x,val;
		scanf("%d %d",&x,&val);
		change(1,x,1.0*val/x);
		printf("%d\n",ans(1));
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值