poj3277city,离散化+线段树 或 stl的multiset

题意:给定每个矩形的高度以及底边在数轴上的起点和终点。各矩形间可能有重叠。问它们覆盖的总面积是多少。


离散化后线段树,数组下标排序,unique去重,lower_bound二分查找数组下标

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<utility>
using namespace std;
typedef long long ll;
struct aa
{
	int l,r,h;
}a[4*100000+9];
int n,nn;
int x[100009],y[100009],h[100009];
int q[100009];
void build(int i,int l,int r)
{
	a[i].l=l;a[i].r=r;
	a[i].h=0;
	if (l+1==r) return;
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid,r);
}
void updata(int i,int l,int r,int k)
{
	if (a[i].l==l&&a[i].r==r)
	{
		a[i].h=max(a[i].h,k);
		return ;
	}
	if (a[i].l+1==a[i].r) return ;
	int mid=(a[i].l+a[i].r)>>1;
	if (a[i].h>0) 
	{
		a[i<<1].h=max(a[i<<1].h,a[i].h);
		a[i<<1|1].h=max(a[i<<1|1].h,a[i].h);
		a[i].h=0;
	}//lazy思想
	if (mid>=r) updata(i<<1,l,r,k);
	else if (mid<=l) updata(i<<1|1,l,r,k);
	else updata(i<<1,l,mid,k),updata(i<<1|1,mid,r,k);
}
ll find(int i)
{
	if (a[i].l+1==a[i].r)
	{
		return (ll)(q[a[i].r]-q[a[i].l])*(a[i].h);
	}
	if (a[i].h>0) 
	{
		a[i<<1].h=max(a[i<<1].h,a[i].h);
		a[i<<1|1].h=max(a[i<<1|1].h,a[i].h);
		a[i].h=0;
	}
	return find(i<<1)+find(i<<1|1); 
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&x[i],&y[i],&h[i]);
		q[i*2]=x[i];
		q[i*2-1]=y[i];
	}
	sort(q+1,q+2*n+1);
	nn=unique(q+1,q+2*n+1)-(q+1);
	build(1,1,nn);
	int l,r;
	for (int i=1;i<=n;i++) 
	{
		l=lower_bound(q+1,q+nn+1,x[i])-q;
		r=lower_bound(q+1,q+nn+1,y[i])-q;
		updata(1,l,r,h[i]);
	}
	ll ans=find(1);
	printf("%lld",ans);
	return 0;
}

set就可以完成这件事
将2*n个点进行排序 记录好是左端点还是右端点
关键是维护当前的高度是多少
set支持插入 删除 还有查询最大值 非常好
 然后依次扫描 如果是左端点 就插入高度
 反之删除高度  

同时代码中运用各种以stl为基础的技巧

#define debug(x) cout<<#x<<"="<<x<<endl


#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<utility>
#include<set>
#define MK(x,y) make_pair(x,y)//make_pair
#define fi first//第一关键字
#define debug(x) cout<<#x<<"="<<x<<endl//黑科技debug
<pre name="code" class="cpp">#define se second//第二关键字
#define inf 0x3f3f3f3fusing namespace std;typedef pair<int,int> pii;//简化typedef long long ll;int n; pair<pii,bool> a[500009];int main(){scanf("%d",&n);int x,y,z;for (int i=1;i<=n;i++){scanf("%d%d%d",&x,&y,&z);a[i].fi.fi=x;a[i+n].fi.fi=y;a[i].fi.se=a[i+n].fi.se=z;a[i].se=true;a[i+n].se=false;}sort(a+1,a+n*2+1);multiset<int> s;multiset<int>::iterator it; s.insert(0);ll ans=0;for (int i=1;i<=2*n;i++){ans+=(ll)(a[i].fi.fi-a[i-1].fi.fi)*(*s.rbegin());//最大的数,*s.rbegin代表最后一个数字,也就是最大一个if (a[i].se) s.insert(a[i].fi.se);else it=s.find(a[i].fi.se),s.erase(it);}printf("%lld",ans);return 0;}

 



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值