bzoj2957: 楼房重建,分块

题目链接:2957: 楼房重建

分块没学过的可以看,分块入门。

题解:把房子分成√n块每块里面维护一个递增的子序列,每次更新之后,在每一个小块内二分查找第一个大于前面最大的斜率,开始斜率为0,每次找完一块更新一次,暴力加进答案。

#include<bits/stdc++.h>
#include<set>
#include<iostream>
#include<string>
#include<iomanip>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define pb push_back
#define mp make_pair
#define ll long long
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
typedef unsigned long long ull;
const int mod=1e9+7;
const int maxn=1e5+5;
const ll inf=0x3f3f3f3f;
const int block=550;
using namespace std;
struct bloc
{
    int cnt;
    double s[1000];
}a[1000];
int n,m,num,belong[maxn],l[maxn],r[maxn];
double y;int x;
double xl[maxn];
void built()
{
    num=n/block;if(n%block)num++;
    for(int i=1;i<=n;i++)
    {
        belong[i]=((i-1)/block)+1;
    }
    for(int i=1;i<=num;i++)
    {
        l[i]=(i-1)*block+1;r[i]=i*block;
    }
    r[num]=n;
}
int slove(int x,double y)
{
    xl[x]=(double)y/x;int p=belong[x];
    double last=0.0;
    int cnt=0;
    for(int i=l[p];i<=r[p];i++)
    {
        if(xl[i]>last)last=a[p].s[cnt++]=xl[i];
    }
    a[p].cnt=cnt;
    int ans=a[1].cnt;last=a[1].s[a[1].cnt-1];
    for(int i=2;i<=num;i++)
    {
        int p=0;
        p=upper_bound(a[i].s,a[i].s+a[i].cnt,last)-a[i].s;
        ans+=(a[i].cnt-p);
        last=max(a[i].s[a[i].cnt-1],last);
    }
    return ans;
}
int main()
{
    scanf("%d %d",&n,&m);
    built();
    while(m--)
    {
        scanf("%d %lf",&x,&y);
        printf("%d\n",slove(x,y));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lhclqslove/p/8400671.html

时间: 2024-09-29 08:27:46

bzoj2957: 楼房重建,分块的相关文章

【BZOJ2957】楼房重建 分块水题

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43406043"); } 题解: 分块水题. 不懂看代码: #include <cmath> #include <cstdio> #include <cstring> #include <iostream>

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

问题: 小 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天.初始时,所有楼房都

[数据结构]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