[POJ 3277]City Horizon

City Horizon
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 17031 Accepted: 4646

Description

Farmer John has taken his cows on a trip to the city! As the sun sets, the cows gaze at the city horizon and observe the beautiful silhouettes formed by the rectangular buildings.

The entire horizon is represented by a number line with N (1 ≤ N ≤ 40,000) buildings. Building i's silhouette has a base that spans locations Ai through Bi along the horizon (1 ≤ Ai < Bi ≤ 1,000,000,000) and has height Hi (1 ≤ Hi ≤ 1,000,000,000). Determine the area, in square units, of the aggregate silhouette formed by all N buildings.

Input

Line 1: A single integer:  N 
Lines 2.. N+1: Input line  i+1 describes building  i with three space-separated integers:  AiBi, and  Hi

Output

Line 1: The total area, in square units, of the silhouettes formed by all  N buildings

Sample Input

4
2 5 1
9 10 4
6 8 2
4 6 3

Sample Output

16

Hint

The first building overlaps with the fourth building for an area of 1 square unit, so the total area is just 3*1 + 1*4 + 2*2 + 2*3 - 1 = 16.

Source




题目大意:地平线上有城市挡住阳光的影子,求所有城市挡住的面积


=>求矩形面积并问题,虽然这个问题是建立于x轴上的,但是我们也可以用面积并求解

数据范围问题:横纵坐标都很大,但是注意到矩形是只有N个的,所以水平线段只有2*N条。故处理的时候要离散化一下
注意用long long

矩形拆线段:
将n个矩形拆成2*n条水平线段,按高度排序,直接统计就可以了(关于面积并问题网上有很多详解)

对于这个问题我对线段树有了新的理解:
首先一个矩形,它的两个横坐标不可能相等,所以我们可以用线段来当做线段树的节点(虽然以前木有打过,,水。。)
然后,对于每一条线段,都有与之对应的线段删除掉,所以我们并不需要pushdown函数,因为等到它对应的线段来了以后,它自然就消失不见咯

对于维护cov域(即节点覆盖数)和len域(实际长度)的维护:
add操作:
当cov域++时,对应的len域即离散前的实际整条线段长度
回溯时计算一下根节点的len域(此时不用管cov域,因为它代表着一条线段)
del操作
当cov域--时,如果为叶子节点则len域=0
否则tree[id].len=tree[id<<1].len+t[id<<1|1].len

对于面积计算:
area+=(b[i].h-b[i-1].h)*t[1].len;


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>

#define maxn 100010
using namespace std;
typedef long long ll;
int n;
struct XD{
	ll l,r,h;
	bool flag;
	bool operator<(const XD& k)const{return h<k.h;}
	//0->入 1->出 
}b[maxn];
ll tmp[maxn],cnt;
struct Tree{
	int l,r,cov;
	ll len;
}t[maxn*4];
void build(int id,int l,int r){
	t[id].l=l,t[id].r=r;
	if(l+1==r)return;
	int mid=(l+r)>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid,r);
}
void add(int id,int l,int r){
	if(t[id].l==l&&t[id].r==r){
		t[id].cov++;
		t[id].len=tmp[r]-tmp[l];
		return;
	}
	int mid=(t[id].l+t[id].r)>>1;
	if(l>=mid)add(id<<1|1,l,r);
	else if(r<=mid)add(id<<1,l,r);
	else{
		add(id<<1,l,mid);
		add(id<<1|1,mid,r);
	}
	if(!t[id].cov)t[id].len=t[id<<1].len+t[(id<<1)+1].len;
}
void del(int id,int l,int r){
	if(t[id].l==l&&t[id].r==r){
		t[id].cov--;
		if(t[id].cov==0)
			if(l+1==r)t[id].len=0;
			else t[id].len=t[id<<1].len+t[id<<1|1].len;			
		return;
	}
	int mid=(t[id].l+t[id].r)>>1;
	if(l>=mid)del(id<<1|1,l,r);
	else if(r<=mid)del(id<<1,l,r);
	else{
		del(id<<1,l,mid);
		del(id<<1|1,mid,r);
	}
	if(!t[id].cov)t[id].len=t[id<<1].len+t[id<<1|1].len;
}
int main(){
	scanf("%d",&n);
	ll x,y,h;
	for(int i=1;i<=n;i++){
		scanf("%lld%lld%lld",&x,&y,&h);
		tmp[++cnt]=x;tmp[++cnt]=y;
		int p=(i<<1)-1;
		b[p].l=x;b[p].r=y;b[p].h=0;b[p].flag=false;
		p=i<<1;b[p].l=x;b[p].r=y;b[p].h=h;b[p].flag=true;
	}
	sort(b+1,b+1+2*n);
	sort(tmp+1,tmp+1+cnt);
	cnt=unique(tmp+1,tmp+1+cnt)-tmp-1;
	build(1,1,cnt);	
	ll area=0;
	for(int i=1;i<=2*n;i++){
		area+=(b[i].h-b[i-1].h)*t[1].len;
		int l,r;
		l=lower_bound(tmp+1,tmp+1+cnt,b[i].l)-tmp;
		r=lower_bound(tmp+1,tmp+1+cnt,b[i].r)-tmp;
		if(!b[i].flag)add(1,l,r);
		else del(1,l,r);
	}
	printf("%lld",area);
	return 0;
} 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值