BZOJ 2957 楼房重建 (线段树)

题目链接  楼房重建

解题思路:我们可以把楼房的最高点的斜率计算出来。那么问题就转化成了实时查询x的个数,满足数列x的左边没有大于等于x的数。

我们可以用线段树维护

设t[i]为如果只看这个区间,可以看到的楼房数量有多少。

f[i]为这个区间的x的最大值

更新的时候我们递归讨论。

计算t[i]时,区间的前一半直接套t[i << 1]的结果,但是后一半受前一半区间的最大值的影响,要分开求解。

query(i, L, R, val)为当前区间中大于val的数的个数(val并不在这个区间内而在这个区间的左边)

然后输出t[1](即整个数列的满足题意的个数)即可。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define lson		i << 1, L, mid
#define	rson		i << 1 | 1, mid + 1, R

typedef long long LL;

const int N = 4e5 + 10;

double x, y;
int n, m;
double f[N];
int t[N];

int query(int i, int L, int R, double val){
	if (L == R) return val < f[i];
	int mid = (L + R) >> 1;
	if (val >= f[i << 1]) return query(rson, val);
	return t[i] - t[i << 1] + query(lson, val); //巧妙的分类讨论
}

void update(int i, int L, int R, int x, double val){
	if (L == R){
		t[i] = 1;
		f[i] = val;
		return;
	}

	int mid = (L + R) >> 1;
	if (x <= mid) update(lson, x, val);
	else update(rson, x, val);
	f[i] = max(f[i << 1], f[i << 1 | 1]); //更新该区间的最大值
	t[i] = t[i << 1] + query(i << 1 | 1, mid + 1, R, f[i << 1]); //更新该区间的符合题意的数量
}

int main(){

	scanf("%d%d", &n, &m);
	rep(i, 1, m){
		scanf("%lf%lf", &x, &y);
		update(1, 1, n, (int)(x + 0.5), y / x); //更新
		printf("%d\n", t[1]);
	}	

	return 0;
}
时间: 2024-09-30 07:40:24

BZOJ 2957 楼房重建 (线段树)的相关文章

bzoj 2957: 楼房重建 线段树

2957: 楼房重建 Time Limit: 10 Sec  Memory Limit: 256 MB[Submit][Status][Discuss] Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些事件发生在一个二维平面上.小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表示,其中Hi为第i栋楼房的高度.

bzoj 2957 楼房重建 (线段树+思路)

链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2957 思路: 用分块可以很简单的过掉,但是这道题也可以用线段树写. 分类讨论左区间最大值对右区间取值的影响,这样每次都只计算左右区间其中一个,复杂度就降成了logn. 实现代码: #include<bits/stdc++.h> using namespace std; #define ll long long #define lson l,m,rt<<1 #define r

bzoj 2957: 楼房重建.

2957: 楼房重建 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2303  Solved: 1088[Submit][Status][Discuss] Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些事件发生在一个二维平面上.小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和

[BZOJ 2957]楼房重建(线段树)

Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些事件发生在一个二维平面上.小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表示,其中Hi为第i栋楼房的高度.如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的.施工队的建造总共进行了M天.初始时,所有楼房都还

bzoj2957 楼房重建——线段树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2957 线段树维护两个值:cnt 能看到的最多楼房数: mx 最大斜率数: 对于一段区间,从左子区间的角度出发来限制右子区间,得到总区间的 cnt 和 mx: 转移时关注新斜率和左右子区间最大斜率的关系即可. 代码如下: #include<iostream> #include<cstdio> #include<cstring> using namespace std

[Luogu P4198]楼房重建(线段树)

题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些事件发生在一个二维平面上.小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段 表示,其中Hi为第i栋楼房的高度.如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的. 施工队的建造总共进行了M天.初始时,所有楼房都还没有开始建

bzoj2957楼房重建——线段树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2957 线段树维护原点到楼顶的斜率,可以知道答案就是从原点开始斜率递增的个数: 记录一个mx数组表示这一段上最大的斜率,二分,分类讨论,递归求解: 而且如果要取rs的长度,不是直接取tr[rs],而是总长度减去tr[ls],因为不能从右边一段的起点开始-- 代码如下: #include<iostream> #include<cstdio> #include<cstring

BZOJ 2957楼房重建

线段树 //Twenty #include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<queue> #include<vector> #define lc x<<1 #define rc x<<1|1 #define

[bzoj2957][楼房重建] (线段树)

Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些事件发生在一个二维平面上.小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表示,其中Hi为第i栋楼房的高度.如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的. 施工队的建造总共进行了M天.初始时,所有楼房都