随笔 - 97, 文章 - 22, 评论 - 81, 引用 - 0
数据加载中……

PKU 3277 City Horizon

题目链接:http://poj.org/problem?id=3277
/*
题意:
    给定N(N <= 40000)个矩形,求它们的面积并。

解法:
离散化+线段树

思路:
    矩形面积并的nlog(n)经典算法。首先我们将每个矩形的纵向边投
影到Y轴上,这样就可以把矩形的纵向边看成一个闭区间,用线段树来
维护这些矩形边的并。现在求的是矩形的面积并,于是可以枚举矩形的
x坐标,然后检测当前相邻x坐标上y方向的合法长度,两者相乘就是其中
一块面积,枚举完毕后就求得了所有矩形的面积并。
    我的线段树结点描述保存了以下信息:区间的左右端点、结点所在
数组编号(因为采用静态结点可以大大节省申请空间的时间)、该结点
被竖直线段完全覆盖的次数Cover和当前结点的测度。测度是指相邻x坐
标之间有效的y方向的长度的和(要求在该区间内)。于是重点就在于
如何维护测度,我们将一个矩形分成两条竖直线段来存储,左边的边称
为入边,右边的边则为出边,然后把所有这些竖直线段按照x坐标递增排
序,每次进行插入操作,因为坐标有可能不是整数,所以必须在做这些
之前将y方向的坐标离散化到数组中,每次插入时如果当前区间被完全覆
盖,那么就要对Cover域进行更新,入边+1,出边-1。更新完毕后判断当
前结点的Cover域是否大于零,如果大于零那么当前节点的测度就是结点
管理区间在y轴上的实际长度,否则,如果是叶子节点,那么测度为0,
如果是内部结点,那么测度的值是左右儿子测度的和。这个更新是log(n)
的,所以,总的复杂度就是nlog(n)。
*/


#include 
<iostream>
#include 
<vector>
#include 
<algorithm>
 
using namespace std;

#define maxn 100010
#define ll __int64

struct VLine {
    
int x, y0, y1;
    
int v;
    VLine() 
{}
    VLine(
int _x, int _y0, int _y1, int _v) {
        x 
= _x;
        y0 
= _y0;
        y1 
= _y1;
        v 
= _v;
    }

}
;

int cmp(VLine a, VLine b) {
    
return a.x < b.x;
}


vector
< VLine > Vl;

int tmp[maxn], size, tot;

int n;

int Binary(int val) {
    
int l = 0;
    
int r = tot-1;
    
while(l <= r) {
        
int m = (l + r) >> 1;
        
if(tmp[m] == val)
            
return m;
        
if(val > tmp[m]) {
            l 
= m + 1;
        }
else
            r 
= m - 1;
    }

}


struct Tree {
    
int l, r, root;
    
int nCover;
    
int ylen;

    
void Update();
}
T[maxn*4];

void Tree::Update() {
    
if(nCover) {
        ylen 
= tmp[r] - tmp[l];
    }
else {
        
if(l + 1 == r)
            ylen 
= 0;
        
else
            ylen 
= T[root<<1].ylen + T[root<<1|1].ylen;
    }

}


void Build(int root, int l, int r) {
    T[root].l 
= l;
    T[root].r 
= r;
    T[root].root 
= root;
    T[root].nCover 
= T[root].ylen = 0;
    
if(l + 1 == r)
        
return ;
    
int mid = (l + r) >> 1;
    Build(root
<<1, l, mid);
    Build(root
<<1|1, mid, r);
}


void Insert(int root, int l, int r, int val) {
    
if(l >= T[root].r || T[root].l >= r)
        
return ;

    
if(l <= T[root].l && T[root].r <= r) {
        T[root].nCover 
+= val;
        T[root].Update();
        
return ;
    }

    Insert(root
<<1, l, r, val);
    Insert(root
<<1|1, l, r, val);

    T[root].Update();
}


int main() {
    
int i;
    
while(scanf("%d"&n) != EOF) {
        Vl.clear();
        size 
= tot = 0;
        tmp[size
++= 0;

        
for(i = 0; i < n; i++{
            
int x0, x1, y;
            scanf(
"%d %d %d"&x0, &x1, &y);
            Vl.push_back(VLine(x0, 
0, y, 1));
            Vl.push_back(VLine(x1, 
0, y, -1));
            tmp[size
++= y;
        }


        sort(Vl.begin(), Vl.end(), cmp);
        sort(tmp, tmp 
+ size);

        
for(i = 0; i < size; i++{
            
if(!|| tmp[i] != tmp[i-1]) {
                tmp[tot
++= tmp[i];
            }

        }


        ll ans 
= 0;
        Build(
10, tot-1);

        
for(i = 0; i < Vl.size(); i++{
            
if(i) {
                ans 
+= (ll)(Vl[i].x - Vl[i-1].x) * T[1].ylen;
            }

            Insert(
1, Binary(Vl[i].y0), Binary(Vl[i].y1), Vl[i].v);
        }


        printf(
"%I64d\n", ans);
    }


    
return 0;
}

posted on 2011-04-03 19:09 英雄哪里出来 阅读(1183) 评论(0)  编辑 收藏 引用 所属分类: 线段树


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理