poj 3277 city horizon 线段树

 http://poj.org/problem?id=3277

poj 3277 city horizon

 

注意数组大小为离散出点的四倍………………

 

#include<iostream>
#include<cstdio>
#include<queue>
#include <algorithm>
#include <cmath>
using namespace std;
struct node1{
    int p, num, id ; //p 原本坐标     id 离散坐标    num 原始编号
}leaf[80010];            //离散出为8000点,而非4000
struct node{
    int lef, rig, mid, hei;
}tree[320010];          // 数组大小为离散点数3~4倍
int n, hush[80010], height[40010], mm;
bool cmp1( node1 x, node1 y){
    if( x.p== y.p) return x.num< y.num;
    return x.p< y.p;
}
bool cmp2( node1 x, node1 y){
    return x.num< y.num;
}
int max( int x, int y){
    return x>y?x:y;
}
void init(){
    int i, j, k, l, r, h, temp;
    for( i=0; i<n; i++){
        scanf("%d%d%d", &l, &r, &h);
        leaf[2*i].p= l;
        leaf[2*i+ 1].p= r;
        leaf[2*i].num=2*i;
        leaf[2*i+ 1].num= 2*i+1;
        height[i]= h;
    }
    sort( leaf, leaf+ 2*n, cmp1);
    hush[0]= leaf[0].p, leaf[0].id= 0;       //数据过大,离散化
    temp= 0;
    for( i=1; i<2*n; i++){
        if( leaf[i].p!= leaf[i-1].p){      //离散时注意相同值节点
            temp++;
            hush[temp]= leaf[i].p;
        }
        leaf[i].id= temp;
    }
    mm= temp;
    sort( leaf, leaf+ 2*n, cmp2);
}
void maketree( int lef, int rig, int num){   //建立线段树
    tree[num].hei= 0;
    tree[num].lef= lef;
    tree[num].rig= rig;
    tree[num].mid= ( lef+ rig)/2;
    if( lef+1 != rig){
        maketree( lef, tree[num].mid, num*2);
        maketree( tree[num].mid, rig, num*2+1);
    }
}
void insert( int lef, int rig, int hei, int num){  //插入
   // cout<<hush[lef]<<" "<<hush[rig]<<" "<<hei<<" "<<num<<endl;
    //cout<<lef<<" "<<rig<<endl;
    if( lef== tree[num].lef && rig== tree[num].rig ){
        tree[num].hei= max( tree[num].hei, hei);
        return ;
    }
    if( rig<= tree[num].mid)        //注意处理边界
        insert( lef, rig, hei, 2*num);
    else if( lef>= tree[num].mid)
        insert( lef, rig, hei, 2*num+1);
    else{
        insert( lef, tree[num].mid, hei, num*2);
        insert( tree[num].mid, rig, hei, num*2+1);
    }
}
long long cal(int num, int h){       //求和
    /*父节点一定可以覆盖子节点,由于更新线段树时,
    遇见l==tree[num].lef && r== tree[num].rig时,
    更新后即return,而未处理子节点,
    所以存在父节点与子节点高度不同的情况,
    若父节点高度大于子节点,则更新子节点高度为父节点值,
    但可能存在子节点高度大于父的情况,故一定要到子节点才可计算面积*/
    if( h> tree[num].hei) tree[num].hei= h;
    if( tree[num].lef+1 == tree[num].rig)
        return (long long)(hush[tree[num].rig]- hush[tree[num].lef] )*(long long )(tree[num].hei);
    return cal( num*2, tree[num].hei) + cal( num*2+1, tree[num].hei);
}
int main(){
   // freopen("1.txt", "r", stdin);
    int i, j;
    scanf("%d", &n);
    init();
    maketree( 0, mm, 1);
    for( i=0; i<2*n; i+= 2){//cout<<i<<endl;
        insert( leaf[i].id, leaf[i+1].id, height[i/2], 1);
    }
    printf("%lld\n", cal(1, -1));
    return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值