[USACO07OPEN]城市的地平线City Horizon --- 线段树 + 扫描线

传送门洛谷P2061


题目描述

版本一:约翰带着奶牛去都市观光。在落日的余晖里,他们看到了一幢接一幢的摩天高楼的轮廓在地平线 上形成美丽的图案。以地平线为 X 轴,每幢高楼的轮廓是一个位于地平线上的矩形,彼此间可能有 重叠的部分。奶牛一共看到了 N 幢高楼,第 i 幢楼的高度是 Hi,两条边界轮廓在地平线上的坐标是 Ai 到 Bi。请帮助奶牛们计算一下,所有摩天高楼的轮廓覆盖的总面积是多少。

版本二:有一个数列,初始值均为0,他进行N次操作,每次将数列[ai,bi)这个区间中所有比Hi小的数改为Hi,他想知道N次操作后数列中所有元素的和。


分析

  简易版本的面积并,一段固定,注意开long long
  看到版本二的翻译,也不难想到另一种跟简单的思路,按照高度从小到大排序,直接区间覆盖,最后来一次统一的查询就行了


代码

指针版的线段树 (自从码过splay后,就喜欢用指针简述了)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define IL inline
#define ll long long

using namespace std;

IL int read()
{
    char c = getchar();
    int sum = 0 , k = 1;

    for(; '0' > c || c > '9'; c = getchar())
        if(c == '-') k = -1;

    for(; '0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';

    return sum * k;
}

int n, m;
int num[40005];

struct Seg
{
    int x, k;
    ll y;
    IL Seg(int x_ = 0, ll y_ = 0, int k_ = 0)
    {
        x = x_; y = y_; k = k_;
    }
    friend bool operator < (const Seg &a, const Seg &b)
    {
        return a.x < b.x;
    }
}seg[80005];

struct node
{
    node *lch, *rch;
    ll len;
    int cnt;
    IL node()
    {
        lch = rch = 0; len = cnt = 0;
    }
} *root;

IL void build(node *p, int l, int r)
{
    if(l == r) return ;
    int mid = (l + r) >> 1;
    p->lch = new node; build(p->lch, l, mid);
    p->rch = new node; build(p->rch, mid + 1, r);
}

IL void pushup(node *p, int l, int r)
{
    if(p->cnt > 0)
        p->len = num[r + 1] - num[l];
    else
        p->len = (l == r ? 0 : p->lch->len + p->rch->len);
}

IL void update(node *p, int l, int r, int x, int y, int k)
{
    if(l == x && r == y)
    {
        p->cnt += k;
        pushup(p, l, r);
        return ;
    }
    int mid = (l + r) >> 1;
    if(y <= mid) update(p->lch, l, mid, x, y, k); else
    if(mid < x) update(p->rch, mid + 1, r, x, y, k); else
    {
        update(p->lch, l, mid, x, mid, k);
        update(p->rch, mid + 1, r, mid + 1, y, k);
    }
    pushup(p, l, r);
}

int main()
{
    m = n = read();
    for(int i = 1, x, y, z, k = 0; i <= n; ++i)
    {
        x = read(); y = read(); z = read();
        num[i] = z;
        seg[++k] = Seg(x, z, 1); seg[++k] = Seg(y, z, -1); 
    }
    n <<= 1;
    num[++m] = 0;

    sort(seg + 1, seg + n + 1);
    sort(num + 1, num + m + 1);
    m = unique(num + 1, num + m + 1) - (num + 1);

    root = new node;
    build(root, 1, m - 1);

    ll ans = 0;
    for(int i = 1; i <= n; ++i)
    {
        ans += (seg[i].x - seg[i - 1].x) * root->len;
        seg[i].y = lower_bound(num + 1, num + m + 1, seg[i].y) - num - 1;
        update(root, 1, m - 1, 1, seg[i].y, seg[i].k);
    }

    printf("%lld", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_27121257/article/details/81201081
今日推荐