POJ 3277 City Horizon 线段树

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

题意:给一些矩形,给出长和高,其中长是用区间的形式给出的,有些区间有重叠,最后求所有矩形的面积。

思路:因为矩形的区间范围太大,因此可以离散化,离散化后就是一个线段树的问题了。结点信息包括左端点,右端点,和高度。一般来说,线段树建树有两种方法,一种是区间离散,一种是点离散,以前只写过点离散的,而这道题明显 是区间离散更简单。又学了一点新知识。

代码:

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;

typedef long long LL;
const int N = 40010;
LL ans = 0;
int cnt = 0;
struct tree{
	int lp,rp,hei;
	int getmid(){
	   return (lp + rp) / 2;
	}
}tt[N * 8];
int vv[N * 2];
struct interval{
	int lpos,rpos,hei;
}aa[N];
void built_tree(int lp,int rp,int pos){
	tt[pos].lp = lp;
	tt[pos].rp = rp;
	tt[pos].hei = 0;
	if(lp + 1 == rp)
		return;
	int mid = tt[pos].getmid();
	built_tree(lp,mid,pos*2);
	built_tree(mid,rp,pos*2+1);
}
bool cmp(interval a,interval b){
	return a.hei < b.hei;
}
int binary_search(int lp,int rp,int value){
	while(lp <= rp){
	   int mid = (lp + rp) / 2;
	   if(vv[mid] == value)
		   return mid;
	   else if(vv[mid] > value)
		   rp = mid - 1;
	   else
		   lp = mid + 1;
	}
}
void update(int lp,int rp,int value,int pos){
	if(lp == tt[pos].lp && tt[pos].rp == rp){
	   tt[pos].hei = value;
	   return;
	}
	if(tt[pos].hei >= 0 && tt[pos].rp > tt[pos].lp + 1){
		tt[2*pos].hei = tt[2*pos+1].hei = tt[pos].hei;
		tt[pos].hei = -1;
	}
	int mid = tt[pos].getmid();
	if(rp <= mid)
		update(lp,rp,value,pos * 2);
	else if(lp >= mid)
		update(lp,rp,value,pos * 2 + 1);
	else{
	  update(lp,mid,value,pos * 2);
	  update(mid,rp,value,pos * 2 + 1);
	}
}
long long query(int pos){
	if(tt[pos].hei >= 0){
		return tt[pos].hei * (long long)(vv[tt[pos].rp] - vv[tt[pos].lp]);
	}
	else
		return query(2 * pos) + query(2 * pos + 1);
}
int main(){
	//freopen("1.txt","r",stdin);
	int n;
	while(scanf("%d",&n) != EOF){
	   cnt = 1;
	   memset(vv,0,sizeof(vv));
	   for(int i = 0; i < n; ++i){
	      scanf("%d%d%d",&aa[i].lpos,&aa[i].rpos,&aa[i].hei);
		  vv[cnt++] = aa[i].lpos;
		  vv[cnt++] = aa[i].rpos;
	   }
	   sort(vv + 1,vv + cnt );
	   int k = 0;
	   for(int i = 1; i <= cnt; ++i){
	      if(vv[i] != vv[i-1] || i == 1)
			  vv[++k] = vv[i];
	   }
	   cnt = k - 1;
	   built_tree(1,cnt,1);
	   sort(aa,aa + n, cmp);
	   for(int i = 0; i < n; ++i){
	      int xid = binary_search(1,cnt,aa[i].lpos);
		  int yid = binary_search(1,cnt,aa[i].rpos);
		  update(xid,yid,aa[i].hei,1);
	   }
	   printf("%lld\n",query(1));
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值