bzoj2957楼房重建

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

线段树。每个点记录斜率,要一个单增的序列长度(从1开始)。

线段树每个点记录自己区间的max和单增长度,pushup的时候通过mx [ ls ]判断往哪个儿子递归。

需要注意的是当右儿子的长度全部可以加上是,不能加s [ rs ],因为不一定全在总的单增序列上(只有rs中大于mx[ls]的那一部分);

  所以右儿子的贡献应该是原先总区间的s减去左儿子的s,因为单增序列从最左端开始,总序列中左儿子肯定全在。

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,m,x,s[N<<2];
double z,mx[N<<2];
int dg(int cur,double lm,int l,int r)
{
    if(l==r)return mx[cur]>lm;
    int ls=(cur<<1),rs=(cur<<1|1);
    if(mx[ls]<=lm)return dg(rs,lm,((l+r)>>1)+1,r);
    return dg(ls,lm,l,((l+r)>>1))+s[cur]-s[ls];
}
void pushup(int bh,int l,int r)
{
    int ls=(bh<<1),rs=(bh<<1|1);
    mx[bh]=mx[ls];s[bh]=s[ls];
    if(mx[rs]<=mx[ls])return;
    mx[bh]=mx[rs];
//    printf(" ()l=%d r=%d mx=%lf\n",l,r,mx[bh]);
    s[bh]+=dg(rs,mx[ls],((l+r)>>1)+1,r);
}
void add(int bh,int l,int r)
{
    int mid=((l+r)>>1);
    if(l==r){
        mx[bh]=z;s[bh]=1;//bh,不是l
//        printf("l=%d r=%d mx=%lf s=%d\n",l,r,mx[bh],s[bh]);
        return;
    }
    if(x<=mid)add(bh<<1,l,mid);
    else add(bh<<1|1,mid+1,r);
    pushup(bh,l,r);
//    printf("l=%d r=%d mx=%lf s=%d\n",l,r,mx[bh],s[bh]);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%lf",&x,&z);z/=x;
        add(1,1,n);
        printf("%d\n",s[1]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Narh/p/8969298.html

时间: 2024-11-05 23:37:49

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

[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 楼房重建——线段树

题目: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

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】 2957: 楼房重建 (线段树)

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

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