HDU3255[farm] (扫描线方体体积并)

终于调出来了,恶心死我了- -

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19080

刚恶补扫描线,做了几道入门题,然后继续找题,网上推荐了这道题,就打算来做一下。

恩,题意还是比较简单,求矩形的面积*权值,重叠部分*最大权值。

卧槽,好像挺简单,恩,不对呀,怎么找到最大,于是考虑暴力枚举- -挂了~~~~


抽象一下,把权值pi当成第3维,如果重叠部分最大权值构成的长方体一定在其他权值构成之上.

简而言之,就是求长方体体积并。


思路也不复杂,假设第三维最大为h,把整张图分成h份,每一个单位高度求一个面积并,加起来就好了。

听起来很简单- -             不过确实写起来有点坑爹(找了一份AC代码对拍,然后慢慢调)。


注意以下细节:

①只有三种高度,拆边的时候把每条边高度(权值)记录下来,然后把h排个序,3重循环枚举高度,总的体积为sum,

当前层面积为ans,sum+=ans*(h[i]-h[i-1]),想象一下,就是把体积分成三段,每一段的高度就是h[i]-h[i-1].

当时我没有记录高度,而是记录的种子编号,然后就把高度排了序,结果,你懂的~~~         (一片混乱~)


②每次是对边L中Li.h>=cur.h的,所以需要把当前要操作的边用一个新的东西保存。  然后依次从左往右扫,加入答案。     之前没有进行这一步操作,结果计算ans+=T[1].len[1]*(L[i+1].x-L[i].x)的时候,有可能L[i+1]这条边是不在当前层的,就bug了。


注意一下细节,然后就轻松打出二维时候的扫描线矩形面积并,就ok了!


AC代码:(人懒,替换了所有的Int为LL,空间有点大)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
const LL maxn=100000+20;
const LL k=1;
/*
体积并 
*/
LL n,m;
LL h[5];
struct line
{
	LL x,y1,y2,flag,h;
	line(LL x,LL y1,LL y2,LL flag,LL h)
	{
		this->x=x;
		this->y1=y1;
		this->y2=y2;
		this->flag=flag;
		this->h=h;
	}
	bool operator<(const line&p)const
	{
		return x<p.x;
	}
};
vector<line>L;
vector<line>N;
LL det[2*maxn];
LL tot;
LL find(LL x)
{
	return lower_bound(det+1,det+tot+1,x)-det;
}
struct node
{
	LL l,r,flag;
	LL len[5];
	void set(LL l,LL r,LL flag)
	{
		this->l=l;
		this->r=r;
		this->flag=flag;
	}
}T[8*maxn];
void pushup(LL i)
{
	LL l=T[i].l;
	LL r=T[i].r;
	for(LL j=0;j<=k;j++)T[i].len[j]=0;
	if(l==r)
	{
		LL t=min(T[i].flag,k);
		T[i].len[t]=det[l+1]-det[l];
	}
	else
	{
		for(LL j=0;j<=k;j++)
		{
			LL t=min(T[i].flag+j,k);
			T[i].len[t]+=T[i<<1].len[j]+T[i<<1|1].len[j];
		}
	}
}
void build(LL i,LL l,LL r)
{
	T[i].set(l,r,0);
	if(l==r)
	{
		pushup(i);
		return ;
	}
	LL mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	pushup(i);
}
void updata(LL i,LL L,LL R,LL x)
{
	LL l=T[i].l;
	LL r=T[i].r;
	if(l>=L&&r<=R)
	{
		T[i].flag+=x;
		pushup(i);
		return ;
	}
	LL mid=(l+r)>>1;
	if(L<=mid)updata(i<<1,L,R,x);
	if(R>mid)updata(i<<1|1,L,R,x);
	pushup(i);
}
int main()
{
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	LL cas;
	scanf("%I64d",&cas);
	LL x1,y1,x2,y2,p;
	for(LL yu=1;yu<=cas;yu++)
	{
		tot=0;
		L.clear();
		scanf("%I64d%I64d",&n,&m);
		for(LL i=1;i<=m;i++)scanf("%I64d",&h[i]);		
		for(LL i=1;i<=n;i++)
		{
			scanf("%I64d%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2,&p);
			L.push_back(line(x1,y1,y2,1,h[p]));
			L.push_back(line(x2,y1,y2,-1,h[p]));
			det[++tot]=y1;
			det[++tot]=y2;
		}
		sort(L.begin(),L.end());
		sort(det+1,det+tot+1);
		sort(h+1,h+m+1);
		LL t=tot;
		tot=unique(det+1,det+t+1)-det-1;	
		LL sum=0;	
		for(LL gh=1;gh<=m;gh++)
		{
			build(1,1,tot);
			LL ans=0;
			N.clear();
			for(LL i=0;i<L.size();i++)
			{
				if(L[i].h>=h[gh])
				{
					N.push_back(L[i]);
				}				
			}
			for(LL i=0;i<N.size()-1;i++)
			{
				LL l=find(N[i].y1);
				LL r=find(N[i].y2);
				updata(1,l,r-1,N[i].flag);
				LL yt=N[i+1].x-N[i].x;
				ans+=T[1].len[k]*yt;
			}
			
			sum+=ans*(h[gh]-h[gh-1]);
		}
		printf("Case %I64d: %I64d\n",yu,sum);
	} 
	return 0;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值