• [题目] luogu P2061 [USACO07OPEN]城市的地平线City Horizon


    算法

    线段树 + 离散化

    思路

    \((x,y,h)\)的左右端点\(x,y\)进行离散化,离散化前的原值记为\(val[i]\),对每个矩形按高度\(h\)从小到大排序。

    设离散化后的端点有\(M\)个,则对如图所示\(M-1\)个规则矩形编号为\([1,M-1]\),可以由\(h_{[i, i+1]}\times(val[i+1] - val[i])\)得出第\(i\)个矩形的面积。

    开一颗区间为\([1,M-1]\)的线段树,按\(h\)从小到大依次对线段树区间覆盖,可以保证高的矩形覆盖了低的矩形的区间,具体操作为对离散化后的\((x,y,h)\),进行线段树\([x,y-1]\)区间覆盖\(h\)值,最终\(i\)点存储\(h_{[i,i+1]}\)的最大值。

    \(h_{[i, i+1]}\)可以通过线段树单点查询\(i\)点求出。

    答案:\(\sum_{i=1}^{M-1}h_{[i, i+1]}\times(val[i+1] - val[i])\)

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define ll long long
    
    using namespace std;
    const int N = 80005;
    int n, b[N], val[N];//b[]:离散化数组
    struct Line { int x, y, h; }a[N];//存储每个矩形
    bool cmp(Line a, Line b) { return a.h < b.h; }
    int ans[N << 2];//线段树数组
    #define ls (p << 1)
    #define rs (p << 1 | 1)
    #define mid ((l + r) >> 1)
    void update(int p, int l, int r, int ul, int ur, int k)
    {
    	if(ul <= l && r <= ur) { ans[p] = k; return; }
    	if(ans[p]) ans[ls] = ans[rs] = ans[p], ans[p] = 0;//区间覆盖直接下推
    	if(ul <= mid) update(ls, l, mid, ul, ur, k);
    	if(ur > mid) update(rs, mid + 1, r, ul, ur, k);
    }
    ll query(int p, int l, int r, int x)//单点查询
    {
    	if(l == r) return ans[p];
    	if(ans[p]) ans[ls] = ans[rs] = ans[p], ans[p] = 0;//区间覆盖直接下推
    	if(x <= mid) return query(ls, l, mid, x);
    	if(x > mid) return query(rs, mid + 1, r, x);
    }
    #undef ls
    #undef rs
    #undef mid
    int main()
    {
    	scanf("%d", &n);
    	for(int i = 1; i <= n; i++)
    	{
    		scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].h);
    		b[i] = a[i].x; b[n + i] = a[i].y;//离散化数组记录下所有x,y
    	}
    	sort(b + 1, b + 2 * n + 1);//排序
    	int _n = unique(b + 1, b + 2 * n + 1) - (b + 1);//去重,_n为去重后x,y端点个数
    	for(int i = 1; i <= n; i++)
    		if(a[i].x != a[i].y)//x=y没有作用
    	{
    		int x = a[i].x, y = a[i].y;
    		a[i].x = lower_bound(b + 1, b + _n + 1, a[i].x) - b;
    		a[i].y = lower_bound(b + 1, b + _n + 1, a[i].y) - b;//离散化
    		val[a[i].x] = x; val[a[i].y] = y;//原值
    	}
    	sort(a + 1, a + n + 1, cmp);//按h从小到大排序
    	for(int i = 1; i <= n; i++)
    		if(a[i].x != a[i].y)//防止y-1<x
    			update(1, 1, _n - 1, a[i].x, a[i].y - 1, a[i].h);//更新,注意结点个数是_n-1,端点y要变成矩形区域y-1,可以画图理解一下,相当于把端点x右边的矩形区域编号为x
    	ll res = 0;
    	for(int i = 1; i < _n; i++)
    		res += query(1, 1, _n - 1, i) * (val[i + 1] - val[i]);
    	printf("%lld\n", res);
    	return 0;
    }
    
    
  • 相关阅读:
    QTP的那些事学习QTP必备的网站整理
    QTP的那些事最新特性总结和支持chrome浏览器
    VBS可扩展类库语音库
    VBS进价编程必须学会的WMI介绍
    QTP的那些事有关datatable对象的使用
    QTP的那些事—wscript.quit使用
    QTP的那些事回放的时候出现了the selected object cannot be found in the aplication.check that the applicaton is open to the
    WMI的基础介绍在vbs中的使用方式
    JS开发利器IxEdit傻瓜式JavaScript开发工具(附下载、汉化版、视频教程)
    QTP的那些事支持chrome浏览器及其chrome插件下载地址
  • 原文地址:https://www.cnblogs.com/shiokiri/p/10492455.html
Copyright © 2020-2023  润新知