ZOJ 3299 Fall the Brick(成段更新)

题意:有n排板砖,m个木板,边界的l和r的n列板砖从天上掉下来,然后有m个边界的a,b的高度为h的木板去接那些板砖,一排板砖中的部分板砖如果掉到木板上就停止下落,剩下的继续下落,问最后每块木板上有多少块板砖。

        开结构体去存储线段树中节点的信息MLE了。。

        按木板的高度,从低到高,去更新线段树节点对应的木板的编号。

        板砖落下时,将对应区间的覆盖次数加一。

        最后查询的时候,如果已经是叶子结点,或者这个区间的对应的木板的编号是确定的,那么就要在对应的木板编号上加上,覆盖次数乘以区间长度的值。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

typedef long long LL;
const int N=100005;
#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define MID(a,b) (a+((b-a)>>1))

vector<int> Y;
map<int,int> H;
LL ans[N];
int l[N],r[N];

struct BOARD
{
	int x,y,h,ind;
	void get()
	{
		scanf("%d%d%d",&x,&y,&h);
		Y.push_back(x); Y.push_back(y);
	}
	bool operator<(const BOARD &b)const
	{
		return h<b.h;
	}
}board[N];
struct Segtree
{
	int color[N*4*4],sum[N*4*4];
	void PushDown(int ind)
	{
		if(color[ind])
		{
			color[LL(ind)]=color[ind];
			color[RR(ind)]=color[ind];
			color[ind]=0;
		}
		if(sum[ind])
		{
			sum[LL(ind)]+=sum[ind];
			sum[RR(ind)]+=sum[ind];
			sum[ind]=0;
		}
	}
	void build(int ind,int lft,int rht)
	{
		memset(color,0,sizeof(color));
		memset(sum,0,sizeof(sum));
	}
	void updata_color(int st,int ed,int col,int ind,int lft,int rht)
	{
		if(st<=lft&&rht<=ed) color[ind]=col;
		else
		{
			PushDown(ind);
			int mid=MID(lft,rht);
			if(st<mid) updata_color(st,ed,col,LL(ind),lft,mid);
			if(ed>mid) updata_color(st,ed,col,RR(ind),mid,rht);
		}
	}
	void updata_sum(int st,int ed,int ind,int lft,int rht)
	{
		if(st<=lft&&rht<=ed) sum[ind]+=1;
		else
		{
			PushDown(ind);
			int mid=MID(lft,rht);
			if(st<mid) updata_sum(st,ed,LL(ind),lft,mid);
			if(ed>mid) updata_sum(st,ed,RR(ind),mid,rht);
		}
	}
	void query(int ind,int lft,int rht)
	{
		if(lft+1==rht||color[ind])
        {
            if(color[ind]) ans[color[ind]]+=(LL)sum[ind]*(Y[rht]-Y[lft]);
        }
		else
		{
			PushDown(ind);
			int mid=MID(lft,rht);
			query(LL(ind),lft,mid);
			query(RR(ind),mid,rht);
		}
	}
}seg;
int main()
{
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		Y.clear(); H.clear();
		memset(ans,0,sizeof(ans));

		for(int i=0;i<n;i++)
		{
			scanf("%d%d",&l[i],&r[i]);
			Y.push_back(l[i]); Y.push_back(r[i]);
		}
		for(int i=0;i<m;i++) board[i].get(),board[i].ind=i+1;

		sort(Y.begin(),Y.end());
		Y.erase(unique(Y.begin(),Y.end()),Y.end());

		int len=(int)Y.size();
		for(int i=0;i<len;i++) H[Y[i]]=i;
		sort(board,board+m);

		seg.build(1,0,len-1);
		for(int i=0;i<m;i++)
		{
			seg.updata_color(H[board[i].x],H[board[i].y],board[i].ind,1,0,len-1);
		}
		for(int i=0;i<n;i++)
		{
			seg.updata_sum(H[l[i]],H[r[i]],1,0,len-1);
		}

		seg.query(1,0,len-1);
		for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
		puts("");
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值