Uva 1232 - SKYLINE ( 线段树 + 区间更新 )

Uva 1232 SKYLINE (线段树 + 区间更新)

题意: 按照顺序在地面上建造放在,每个房子的高度为h,操作 l r h 表示 在(l,r] 区间建立一个高度为h的房子。统计每次建立完房子之后的overlap值之和

overlap值表示[ 修完一座房子之后,统计它在多长的部分是最高的(可以和其他房子并列高) ]如样例图,按照灰、黒。白的顺序建立房子 ans = (11-5) + (5-1) + (5-3) + (13-11) = 6 + 4 + 4 = 14

分析: 一开始一直想不明白如何向下传递,这里实际上Pushdown操作就是普通的懒惰标记PushUp操作用来想上更新minh和maxh

这里需要维护至少两个域 一个是 房子的高度setv 一个是maxh,区间内房子的最大高度。不过从别人的博客看到还有一个优化,就是再开一个minh域,存放区间内房子的最小高度,很显然,如果新建立的房子高度比该区间的minh还小,就不需要更新了。结果用ans进行累加即可,这里要注意,线段是连续的,但是所以区间(l,r]想当于[l+1,r]update的时候注意下,还有就是求ans的时候记得+1

//#define BUG
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <list>
#include <queue>
#include <ctime>
#include <iostream>
#include <cmath>
#include <set>
#include <string>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define INF                 0x7fffffff
#define MAX                 0x3f3f3f3f

#define CLR( a, b )         memset( a, b, sizeof(a) )
#define REP( i, a, b )      for( int i = (a); i < (b); ++i )
#define FOR( i, a, b )      for( int i = (a); i <=(b); ++i )
#define FOD( i, a, b )      for( int i = (a); i >=(b); --i )

#define MID                 ( l + r ) >> 1
#define lson                l, m, o << 1
#define rson                m + 1, r, o << 1 | 1
#define ls                  o << 1
#define rs                  o << 1 | 1
#define MAXN                100010

struct SegTree
{
    int l, r;
    int setv, maxh, minh;

}tree[MAXN << 2];
int ans;

void PushUp( int o )
{
    tree[o].maxh = max( tree[ls].maxh , tree[rs].maxh );
    tree[o].minh = min( tree[ls].minh , tree[rs].minh );
}

void PushDown( int o )
{
    if( tree[o].setv != -1 )        //三个标记往下传
    {
        tree[ls].setv = tree[rs].setv = tree[o].setv;
        tree[ls].maxh = tree[rs].maxh = tree[o].maxh;
        tree[ls].minh = tree[rs].minh = tree[o].minh;
        tree[o].setv = -1;
    }
}

void Build( int l, int r, int o )
{
    tree[o].l = l, tree[o].r = r;
    tree[o].setv = tree[o].maxh = tree[o].minh = 0;
    if( l == r )
        return;
    int m = MID;
    Build( lson );
    Build( rson );
}

void Update( int L, int R, int c, int o )
{
    if( tree[o].minh > c )    return;
    if( tree[o].l == L && tree[o].r == R )
    {
        if( tree[o].maxh <= c )
        {
            tree[o].setv = tree[o].maxh = tree[o].minh = c;
            ans += R - L + 1;
            return;
        }
        if( L == R )  return;
    }

    PushDown( o );
    int m = ( tree[o].l + tree[o].r ) >> 1;
    if( R <= m )  Update( L, R, c, ls );
    else if( L >  m )  Update( L, R, c, rs );
    else
    {
        Update( L, m, c, ls );
        Update( m + 1, R, c, rs );
    }
    PushUp( o );
}

void Orz()
{
    #ifdef  BUG
        freopen("in.txt","r",stdin);
    #endif
    int cas, n;
    int l, r, c;
    while( ~scanf( "%d", &cas ) && cas )
    {
        while( cas-- )
        {
            scanf( "%d", &n );
            Build(1,MAXN,1);
            ans = 0;
            while( n-- )
            {
                scanf( "%d %d %d", &l, & r, &c );
                Update( l + 1, r, c, 1);
            }
            printf( "%d\n", ans );
        }
    }
}

int main()
{
    Orz();
    return 0;
}

代码君

				
时间: 2024-10-25 02:18:53

Uva 1232 - SKYLINE ( 线段树 + 区间更新 )的相关文章

UVA 1232 - SKYLINE(线段树)

UVA 1232 - SKYLINE 题目链接 题意:按顺序建房,在一条线段上,每个房子一个高度,要求出每间房子建上去后的轮廓线 思路:线段树延迟更新,一个setv作为高度的懒标记,此外还要在开一个cover表示当前结点一下是否都为同一高度 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define lson(x) ((x<<1)+1)

HDU 1689 Just a Hook 线段树区间更新求和

点击打开链接 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18894    Accepted Submission(s): 9483 Problem Description In the game of DotA, Pudge's meat hook is actually the most horrible

POJ 2528 Mayor&#39;s posters (线段树区间更新+离散化)

题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值.由于l和r范围比较大,内存就不够了,所以就用离散化的技巧 比如将1 4化为1 2,范围缩小,但是不影响答案. 写了这题之后对区间更新的理解有点加深了,重点在覆盖的理解(更新左右两个孩子节点,然后值清空),还是要多做做题目. 1 #include <iostream> 2 #include <

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

HDU 5023 A Corrupt Mayor&#39;s Performance Art 线段树区间更新+状态压缩

Link:  http://acm.hdu.edu.cn/showproblem.php?pid=5023 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <string> 7 #include <cmath> 8 using namesp

hihocoder 1080 线段树(区间更新)

题目链接:http://hihocoder.com/problemset/problem/1080 , 两种操作的线段树(区间更新). 这道题前一段时间一直卡着我,当时也是基础不扎实做不出来,今天又想了想其实还是比较简单的,也只能怪自己太弱了. 这道题坑就坑在是有两个操作:set和add,所以lazy标记数组就需要两个,但是有一点要考虑的是一个区间上set与add的先后关系——如果对于一个区间set和add标记同时存在,那么应该如果处理:一种情况set在add之前,那么就按照正常顺序来就可以了:

(简单) POJ 3468 A Simple Problem with Integers , 线段树+区间更新。

Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. 题意

HDU 5023 A Corrupt Mayor&#39;s Performance Art(线段树区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5023 解题报告:一面墙长度为n,有N个单元,每个单元编号从1到n,墙的初始的颜色是2,一共有30种颜色,有两种操作: P a b c  把区间a到b涂成c颜色 Q a b 查询区间a到b的颜色 线段树区间更新,每个节点保存的信息有,存储颜色的c,30种颜色可以压缩到一个int型里面存储,然后还有一个tot,表示这个区间一共有多少种颜色. 对于P操作,依次往下寻找,找要更新的区间,找到要更新的区间之前

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d