luogu P1382 楼房

二次联通门 : luogu P1382 楼房

/*
    luogu P1382 楼房

    线段树 + 扫描线 + 离散化
    正解貌似是堆。。。

       MMP。。。二段式线段树各种错误。。。

    离散化一下横坐标
    扫描线扫一下就好。。

    注意判断一个横坐标上对应两个y值的情况。。。
*/
#include <algorithm>
#include <cstdio>

#define Max 1000002

void read (int &now)
{
    now = 0;
    bool temp = false;
    register char word = getchar ();
    while (word < ‘0‘ || word > ‘9‘)
    {
        if (word == ‘-‘)
            temp = true;
        word = getchar ();
    }
    while (word >= ‘0‘ && word <= ‘9‘)
    {
        now = now * 10 + word - ‘0‘;
        word = getchar ();
    }
    if (temp)
        now = -now;
}

inline int min (int _Curs_, int ROcs_)
{
    return _Curs_ < ROcs_ ? _Curs_ : ROcs_;
}

inline int max (int _Curs_, int ROcs_)
{
    return _Curs_ > ROcs_ ? _Curs_ : ROcs_;
}

struct Segment_Tree_Data
{
    Segment_Tree_Data *Left, *Right;

    int l, r;
    int key;
    int Flandre;
    int Mid;

    Segment_Tree_Data ()
    {
        Left = NULL;
        Right = NULL;
        key = 0;
        Flandre = 0;
    }
};

struct Data_Type
{
    int l, r;
    int h;

    bool operator < (const Data_Type &now) const
    {
        return now.l < l;
    }
};

struct Point_Data
{
    int x, y;
};

Segment_Tree_Data *Root;

class Segment_Tree_Type
{
    public :

        void Build (Segment_Tree_Data *&now, int l, int r)
        {
            now = new Segment_Tree_Data ();
            now->l = l;
            now->r = r;
            if (l == r)
                return ;
            now->Mid = l + r >> 1;

            Build (now->Left, l, now->Mid);
            Build (now->Right, now->Mid + 1, r);
        }

        void Change_Section (Segment_Tree_Data *&now, int l, int r, int to)
        {
            if (l <= now->l && r >= now->r)
            {
                now->key = max (now->key, to);
                now->Flandre = max (now->Flandre, to);
                return ;
            }
            if (now->Flandre)
            {
                now->Left->key = max (now->Flandre, now->Left->key);
                now->Right->key = max (now->Flandre, now->Right->key);

                now->Left->Flandre = max (now->Flandre, now->Left->Flandre);
                now->Right->Flandre = max (now->Flandre, now->Right->Flandre);

                now->Flandre = 0;
            }
            if (l <= now->Mid)
                Change_Section (now->Left, l, min (now->Mid, r), to);
            if (r > now->Mid)
                Change_Section (now->Right, max (now->Mid + 1, l), r, to);
            now->key = max (now->Left->key, now->Right->key);
        }

        int Query (Segment_Tree_Data *&now, int pos)
        {
            if (now->l == now->r)
                return now->key;
            if (now->Flandre)
            {
                now->Left->key = max (now->Flandre, now->Left->key);
                now->Right->key = max (now->Flandre, now->Right->key);

                now->Left->Flandre = max (now->Flandre, now->Left->Flandre);
                now->Right->Flandre = max (now->Flandre, now->Right->Flandre);

                now->Flandre = 0;
            }
            now->key = max (now->Left->key, now->Right->key);
            if (pos <= now->Mid)
                return Query (now->Left, pos);
            else
                return Query (now->Right, pos);
        }
};

Segment_Tree_Type Tree;

Data_Type data[Max];

int Answer;
int rank[Max << 2];
int N;
int Size, Count;

Point_Data point[Max];

int main (int argc, char *argv[])
{
    read (N);
    for (int i = 1; i <= N; i++)
    {
        read (data[i].h);
        read (data[i].l);
        read (data[i].r);
        rank[++Size] = data[i].l;
        rank[++Size] = data[i].r;
    }
    std :: sort (rank + 1, rank + 1 + Size);
    Size = std :: unique (rank + 1, rank + 1 + Size) - rank - 1;
    Root = NULL;
    Tree.Build (Root, 1, Size);
    for (int i = 1; i <= N; i++)
    {
        data[i].l = std :: lower_bound (rank + 1, rank + 1 + Size, data[i].l) - rank;
        data[i].r = std :: lower_bound (rank + 1, rank + 1 + Size, data[i].r) - rank;
        Tree.Change_Section (Root, data[i].l, data[i].r - 1, data[i].h);
    }

    for (int i = 1; i <= Size; i++)
    {
        point[i].x = rank[i];
        point[i].y = Tree.Query (Root, i);
        if (point[i].y != point[i - 1].y)
            Answer++;
    }
    printf ("%d\n", Answer << 1);
    for (int i = 1; i <= Size; i++)
        if (point[i].y != point[i - 1].y)
        {
            printf ("%d %d\n", point[i].x, point[i - 1].y);
            printf ("%d %d\n", point[i].x, point[i].y);
        }
    return 0;
}    
时间: 2024-12-28 16:04:37

luogu P1382 楼房的相关文章

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

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

[luogu] P4198 楼房重建

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

P1382 楼房

传送门 在同一横坐标,轮廓只会被最高的楼房影响 所以考虑用 $multiset$ 维护当前的每个楼房高度 轮廓线显然只有出现楼房最高高度变化时会出现转折点 把一个楼根据左右边界分成两个东西,左边时把高度加入 $set$,到了右边再从 $set$ 里把该高度删除 每次更新 $set$ 时判断一下高度变化并记录答案就好了 注意每次插入或删除时要把同一横坐标的一起完成,因为同一横坐标最多只会产生一次贡献 #include<iostream> #include<cstdio> #inclu

洛谷 P1382 楼房

题目描述 地平线(x轴)上有n个矩(lou)形(fang),用三个整数h[i],l[i],r[i]来表示第i个矩形:矩形左下角为(l[i],0),右上角为(r[i],h[i]).地平线高度为0.在轮廓线长度最小的前提下,从左到右输出轮廓线. 下图为样例2 输入输出格式 输入格式: 第一行一个整数n,表示矩形个数 以下n行,每行3个整数h[i],l[i],r[i]表示第i个矩形. 输出格式: 第一行一个整数m,表示节点个数 以下m行,每行一个坐标表示轮廓线上的节点.从左到右遍历轮廓线并顺序输出节点

P1382 楼房 set用法小结

这个sb题目,剧毒... STL大法好 首先,我准备用经典的线段树优化扫描线来做.之前的矩形周长把我困了数天导致我胸有成竹. 然后,敲代码半小时,调试半个月......这个,sb,怎么改都是0分+2个RE... 然后我爆炸了,请胡雨菲来帮忙.他还是提议我用set做.然后就set了... 跑的贼慢,不过90分,第八个点日常RE... 但是了解了一点set的用法,让我慢慢道来(嘿) 首先,可以看这个博客. 我自己的理解: 1,这是一种功能有限的搜索树. 2,它有序,资瓷插入删除,但是缓慢 3,这东西

【线段树】[Luogu P4198]楼房修建

显然要维护斜率区间单调递增 并且第一个必选,后一个比前一个选中的斜率大的必选 考虑如何合并两个区间 我们维护一个least值,least这个值必选,且之后选的都必须严格大于least,Push_Up的时候就像在线段树上二分一样做就好了 这样每次Push_Up是$logn$的,线段树单点修改时$logn$的,所以总复杂度是$O(nlog^2n)$的,再维护一个区间最大值可以做到一些不必要但是可以卡常的剪枝... 1 #include<bits/stdc++.h> 2 #define writel

楼房 洛谷1382 &amp;&amp; codevs2995

P1382 楼房 题目描述 地平线(x轴)上有n个矩(lou)形(fang),用三个整数h[i],l[i],r[i]来表示第i个矩形:矩形左下角为(l[i],0),右上角为(r[i],h[i]).地平线高度为0.在轮廓线长度最小的前提下,从左到右输出轮廓线. 下图为样例2. 输入输出格式 输入格式: 第一行一个整数n,表示矩形个数 以下n行,每行3个整数h[i],l[i],r[i]表示第i个矩形. 输出格式: 第一行一个整数m,表示节点个数 以下m行,每行一个坐标表示轮廓线上的节点.从左到右遍历

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

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

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)和