【BZOJ2957】楼房重建 分块水题

#include <stdio.h>
int main()
{
	puts("转载请注明出处谢谢");
	puts("http://blog.csdn.net/vmurder/article/details/43406043");
}

题解:

分块水题。

不懂看代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 101000
#define P 2050
#define eps 1e-10
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m;
double h[N];
int belong[N],size,blocks;
struct Block
{
	double stk[P];
	int top,begin,end;
	void keep(double now=0.0)
	{
		top=0;
		for(int i=begin;i<=end;i++)
			if(h[i]>now)stk[++top]=now=h[i];
	}
	int ask(double now=0.0)
	{
		int pos=(upper_bound(stk+1,stk+top+1,now+eps)-stk);
		return top-pos+1;
	}
}block[P];
inline int ask(double now=0.0)
{
	int ans=0,i;
	for(i=1;i<=blocks;i++)
	{
		ans+=block[i].ask(now);
		now=max(now,block[i].stk[block[i].top]);
	}
	return ans;
}
int main()
{
	int i,a,b;
	scanf("%d%d",&n,&m);
	size=sqrt(n);
	for(i=1;i<=n;i++)
	{
		belong[i]=(i-1)/size+1;
		if(!block[belong[i]].begin)block[belong[i]].begin=i;
		block[belong[i]].end=i;
	}
	blocks=belong[n];
	while(m--)
	{
		scanf("%d%d",&a,&b);
		h[a]=(double)b/a;
		block[belong[a]].keep();
		printf("%d\n",ask());
	}
	return 0;
}
时间: 2024-07-31 03:00:46

【BZOJ2957】楼房重建 分块水题的相关文章

bzoj2957: 楼房重建,分块

题目链接:2957: 楼房重建 分块没学过的可以看,分块入门. 题解:把房子分成√n块每块里面维护一个递增的子序列,每次更新之后,在每一个小块内二分查找第一个大于前面最大的斜率,开始斜率为0,每次找完一块更新一次,暴力加进答案. #include<bits/stdc++.h> #include<set> #include<iostream> #include<string> #include<iomanip> #include<vector

[数据结构]bzoj2957楼房重建

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

楼房重建(分块/线段树)

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

bzoj2957 楼房重建

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

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

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

BZOJ 2597 楼房重建 分块

题目大意:给定n座楼,初始高度为0,每次可以改变某栋楼的高度,求每次改变高度之后从原点可以看到几栋楼 记录每栋楼楼顶与原点连线的斜率 那么一栋楼可见当且仅当前面所有楼的斜率都小于这栋楼 将n栋楼分为√(0.5*n*logn)块 每一块内维护一个单调上升子序列(注意不是LCS) 比如说4 1 2 3 5 那么维护的序列就是4 5 修改的时候块内暴力重建 然后查询顺着块撸一遍 每次记录当前的最大值 然后去下一个块中二分找到第一个比这个最大值大的值 然后统计答案&&更新最大值 #include

BZOJ 2957 楼房重建 分块

题目大意:一个人站在(0,0)处,每次操作都会改变一栋楼的高度,问每次操作之后这个人会看到多少栋楼. 思路:将所有楼分块,在每一块内暴力维护一个单调递增的序列,这样只要这个块中的一栋楼能被看到,那么这一块内能被看到的楼肯定是一段,这样方便统计. 至于是哪一段,二分就可以了. CODE: #define _CRT_SECURE_NO_WARNINGS #include <cmath> #include <cstdio> #include <cstring> #includ

bzoj2957 楼房重建——线段树

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

bzoj2957楼房重建——线段树

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