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

问题:

小 A 的楼房外有一大片施工工地,工地上有 N 栋待建的楼房。每天,这片工地上的房子拆了又建、建了又拆。他经常无聊地看着窗外发呆,数自己能够看到多少栋房子。

为了简化问题,我们考虑这些事件发生在一个二维平面上。小 AA 在平面上 (0,0) 点的位置,第 ii 栋楼房可以用一条连接 (i,0) 和 (i,Hi?) 的线段表示,其中 Hi? 为第 i栋楼房的高度。 如果这栋楼房上存在一个高度大于 0 的点与 (0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。

施工队的建造总共进行了 M 天。初始时,所有楼房都还没有开始建造,它们的高度均为 0 。 在第 i 天,建筑队将会将横坐标为 Xi? 的房屋的高度变为 Yi? (高度可以比原来大—修建,也可以比原来小—拆除,甚至可以保持不变—建筑队这天什么事也没做)。 请你帮小 A 数数每天在建筑队完工之后,他能看到多少栋楼房?

:

注意一些点 

如果是要求修改的 绝大部分是数据结构 

不要再往逆序对上想了啊!

$1$ 线段树

分治 分而治之

cnt代表当前区间内可行的总数

code:

//
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
#define maxnn 700000
int n,m;
struct node
{
    int x,y,cnt;
    double val;
}tree[maxnn];
void build(int p,int a,int b)
{
    tree[p].x=a;
    tree[p].y=b;
    if(a<b)
    {
        int mid=(a+b)/2;
        build(p<<1,a,mid);
        build(p<<1|1,mid+1,b);
    }
}
int  query(int p,double lim)
{
    if(tree[p].val<=lim) return 0;
       if(tree[p].x==tree[p].y) return (tree[p].val>lim);
       int mid=(tree[p].x+tree[p].y)/2;
       if(tree[p<<1].val<=lim) return query(p<<1|1,lim);
       else return tree[p].cnt-tree[p<<1].cnt+query(p<<1,lim); 右边可行的 + 左边门槛大于lim 的
}
void modify(int p,int yY,double d)
{
    if(tree[p].x==tree[p].y) {tree[p].val=d;tree[p].cnt=1;}
    else
    {
        int mid=(tree[p].x+tree[p].y)/2;
        if(yY<=mid) modify(p<<1,yY,d);
        else
        if(yY>mid) modify(p<<1|1,yY,d);
        tree[p].cnt=tree[p<<1].cnt+query(p<<1|1,tree[p<<1].val); 左边没有门槛的 + 右边门槛大于左边最大值的
        tree[p].val=max(tree[p<<1].val,tree[p<<1|1].val);
    }
} 

int main()
{
    cin>>n>>m;
    int x,y;
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        modify(1,x,double(y)/x); 这里卡好久...
        printf("%d\n",tree[1].cnt);
    }
}

$2$ 分块

巨佬代码链接:

https://www.luogu.org/blog/HuangYuhan-Yuzhe/nkoj-0817-zhuan-xiang-lian-xi

原文地址:https://www.cnblogs.com/OIEREDSION/p/11370902.html

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

楼房重建(分块/线段树)的相关文章

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

题目链接  楼房重建 解题思路:我们可以把楼房的最高点的斜率计算出来.那么问题就转化成了实时查询x的个数,满足数列x的左边没有大于等于x的数. 我们可以用线段树维护 设t[i]为如果只看这个区间,可以看到的楼房数量有多少. f[i]为这个区间的x的最大值 更新的时候我们递归讨论. 计算t[i]时,区间的前一半直接套t[i << 1]的结果,但是后一半受前一半区间的最大值的影响,要分开求解. query(i, L, R, val)为当前区间中大于val的数的个数(val并不在这个区间内而在这个区

楼房重建(线段树)

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

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

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

[题解]luogu_P4198_楼房重建(线段树logn合并

前言:最近购买了润滑脂和几个个性键帽,润滑脂用的太多大键稍微有点黏,但是我可以接受,钢丝声基本没有了,虽然没有拆下来卫星轴调试,但是效果还是有的,买了一个原厂高度的空格,好看是好看,用料也挺厚,但是形变非常严重,不过三十块要什么自行车,方向键是个手柄按键三角方块啥的透光键帽,用料也还行,但是字符有很明显的凹陷,看不出来但是摸起来就很明显,而且由于灯在轴的上方导致只有上面一半有光能透出来,但是我也不太在意 线段树update好题,首先把每个点转化为斜率,这样找一个递增序列即可,但是不同点在于这个递

G - 楼房重建 (线段树)

题目链接:https://cn.vjudge.net/contest/281960#problem/G 题目大意:中文问题 具体思路:首先每一个点的值可以用当前这个点的斜率来表示,每一次输入一个值,我们先看当前这个点之前的区域中有多少点是小于当前这个点的斜率的,这样每一次查询就可以了. 查询的时候:首先对于当前的点的左区间,肯定是包含关系,对于右区间的话,需要考虑到左区间会遮挡住右区间的情况. 我们就按照递归的形式,如果说当前的maxx[rt]<=val,我们就再去查询这个区间的右区间,看看这一

bzoj2957: 楼房重建,分块

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

CDOJ 1157 数列(seq) 分块+线段树

数列(seq) Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1157 Description 给出一个长度为n的数列A.现有如下两种操作: 修改操作:把数列中第i个数改为x 询问操作:给定一个位置i,问数列中有多少个位置j ( j>i ),满足位置i与位置j间所有的数都不超过Ai与Aj的较大值. 现共有m个操作,请对每个询问操作做出回答. Input 第一行两个正整数n.m.

BZOJ 2597 楼房重建 分块

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