bzoj2957 楼房重建——线段树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2957

线段树维护两个值:cnt 能看到的最多楼房数; mx 最大斜率数;

对于一段区间,从左子区间的角度出发来限制右子区间,得到总区间的 cnt 和 mx;

转移时关注新斜率和左右子区间最大斜率的关系即可。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=100005;
int n,m,cnt[maxn<<2];
double mx[maxn<<2];
int query(double d,int o,int l,int r)
{
    int ls=(o<<1),rs=(o<<1|1),mid=(l+r)>>1;
    if(l==r)return d<mx[o];
    if(d>mx[ls])return query(d,rs,mid+1,r);
    else return cnt[o]-cnt[ls]+query(d,ls,l,mid);
}
void update(double d,int p,int o,int l,int r)
{
    if(l==r)
    {
        cnt[o]=1; mx[o]=d; return;
    }
    int mid=(l+r)>>1;
    if(p<=mid)update(d,p,o<<1,l,mid);
    else update(d,p,o<<1|1,mid+1,r);
    mx[o]=max(mx[o<<1],mx[o<<1|1]);
//    cnt[o]=query(mx[o],o,l,r);
    cnt[o]=cnt[o<<1]+query(mx[o<<1],o<<1|1,mid+1,r);//右区间受左区间限制
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        update((double)y/x,x,1,1,n);
        printf("%d\n",cnt[1]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/9202573.html

时间: 2024-07-31 03:00:41

bzoj2957 楼房重建——线段树的相关文章

bzoj2957楼房重建——线段树

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

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

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

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栋楼房的高度.

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

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

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

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: 楼房重建,分块

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

bzoj2957楼房重建

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2957 线段树.每个点记录斜率,要一个单增的序列长度(从1开始). 线段树每个点记录自己区间的max和单增长度,pushup的时候通过mx [ ls ]判断往哪个儿子递归. 需要注意的是当右儿子的长度全部可以加上是,不能加s [ rs ],因为不一定全在总的单增序列上(只有rs中大于mx[ls]的那一部分): 所以右儿子的贡献应该是原先总区间的s减去左儿子的s,因为单增序列从最左端开始,总序