【线段树】City Horizon

来源:互联网 发布:非凡软件站安全吗 编辑:程序博客网 时间:2024/06/05 06:58

题意:给出一堆建筑物的左右端点(a,b),范围很大10^9,建筑物都是长方形的且可以相互覆盖,每个建筑物的高度是hi.求这些建筑物总共覆盖的面积。

思路:这题由于建筑物的个数比较多,4*10^4,所以如果暴力枚举o(n^2)的话,肯定会超时的。所以想到用线段树优化来寻找或者标记哪些建筑物相互覆盖,并且在那些建筑物上取相互覆盖中的高度较高者作为被覆盖部分的新的高度。用线段树来执行更改这个动作的话,时间复杂度是lgn的。又由于每个建筑物的左右端点坐标值可能很大,所以线段树的两端点不可能存那么大,也没必要,因为只有40000条线段。所以采用离散化的技术,即把这些大的端点值离散化成1-40000*2范围内的数来表示。建树也能建了。

离散化是一门技术,好的离散化方法在时间和代码复杂度上都很让人感到舒服满意。我离散化的技术不好,像这种是(a,b)成对出现的离散化,我只会用map来暴力,所以时间复杂度很高,不过编码复杂度到是简单。求大牛指教高效美观的离散化。

还有就是,我平时写线段树喜欢把端点写成[x,x]这种模样,不喜欢写成[x,x+1)这种。但这道题,我用前者写的时候,脑袋老是转不动,又想得越来越复杂。。囧。。因为涉及到离散化前后的映射问题。到时采用后者,在某一段端点被更新掉了的情况也不影响,处理很方便。理解不够深入惹的祸。。。


#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#include<map>#include<vector>using namespace std;typedef long long LL;const int N = 40000 + 10;inline char Rstr(){char str[10];scanf("%s",str);return str[0];}map<LL,int>mp;int n;LL a[N],b[N],h[N];int hash[N*2];LL area;vector<LL>v;struct node{    int left,right;    LL height;};node seg_tree[N*8];void creattree(int l,int r,int rt){    seg_tree[rt].left = l;    seg_tree[rt].right = r;    seg_tree[rt].height = 0;    if(l+1==r) return;    int mid = (l+r)>>1;    creattree(l,mid,rt<<1);    creattree(mid,r,rt<<1|1);}void insert(int l,int r,int h,int rt){    if(l==seg_tree[rt].left && r==seg_tree[rt].right)    {        if(seg_tree[rt].height<h || !seg_tree[rt].height)            seg_tree[rt].height = h;        return;    }    int mid = (seg_tree[rt].left + seg_tree[rt].right)>>1;    if(mid>=r) insert(l,r,h,rt<<1);    else if(mid<=l) insert(l,r,h,rt<<1|1);    else    {        insert(l,mid,h,rt<<1);        insert(mid,r,h,rt<<1|1);    }}LL cal(int h,int rt){    if(h>seg_tree[rt].height)        seg_tree[rt].height = h;    if(seg_tree[rt].left+1==seg_tree[rt].right)        return (hash[seg_tree[rt].right]-hash[seg_tree[rt].left])        *seg_tree[rt].height;    return cal(seg_tree[rt].height,rt<<1) + cal(seg_tree[rt].height,rt<<1|1);}int main(){    while(scanf("%d",&n)==1)    {        mp.clear();        v.clear();        area=0;        creattree(1,n*2,1);        int k=1;        for(int i=1;i<=n;i++)        {            scanf("%lld%lld%lld",&a[i],&b[i],&h[i]);            v.push_back(a[i]);            v.push_back(b[i]);        }        sort(v.begin(),v.end());        unique(v.begin(),v.end());        for(int i=0;i<v.size();i++)        {            if(!mp[v[i]])            {                        mp[v[i]]=k;                hash[k++]=v[i];            }        }        for(int i=1;i<=n;i++)        {            //printf("%d %d\n",mp[a[i]],mp[b[i]]);            insert(mp[a[i]],mp[b[i]],h[i],1);        }        area = cal(seg_tree[1].height,1);        cout << area << endl;    }    return 0;}



原创粉丝点击