hdu 4419线段树覆盖面积

/*

和胡浩大牛写的hdu 1255题的大体思路差不多,先把矩形线段化,在一个数轴上覆盖,再枚举另一个数轴求面积(再枚举之前先排好序),只不过这题的状态比较多,要把Pushup函数改一下,这里不仅仅是处理覆盖一次和多次的问题了,还要考虑颜色的重叠问题,处理的时候有点像容斥,用二进制的1,2,4表示r,g,b这样便于处理,最后覆盖过程就大体差不多了;

代码如下:

*/

#include<stdio.h>
#include<string.h>
#include<algorithm>

using namespace std;
const int N=20000;
const int t[8]={0,1,2,4,3,5,6,7};

struct tree{__int64 n[8];} sum[N<<2];
struct seg{ 
	__int64 x1,x2,h,v;
	bool operator <(const seg &tem) const
	{return h<tem.h;}
} line[N];

__int64 X[N];
__int64 cnt[N<<2][4];

void Set(int k,__int64 x1,__int64 y1,__int64 x2,__int64 y2,int v)
{
	X[k]=x1;
	X[k+1]=x2;
	line[k].x1=x1;line[k].x2=x2;line[k].h=y1;line[k].v=v;
	line[k+1].x1=x1;line[k+1].x2=x2;line[k+1].h=y2;line[k+1].v=-v;
}
void Pushup(int i,int l,int r)
{
	int j,R=1,G=2,B=4,k=0;
	__int64 tem;
	if(cnt[i][1]>0)k|=R;
	if(cnt[i][2]>0)k|=G;
	if(cnt[i][3]>0)k|=B;
	memset(sum[i].n,0,sizeof(sum[i].n));
	if(k)
	{
		sum[i].n[k]=X[r+1]-X[l];
		if(l==r)return;
		for(j=1;j<=7;j++)//主要思路在这个循环,这里参考了各个大牛的思路,很简洁,很漂亮;
		{
			if((k|j)!=k){
				tem=sum[i<<1].n[j]+sum[i<<1|1].n[j];
				sum[i].n[k]-=tem;
				sum[i].n[k|j]+=tem;
			}
		}
	}
	else if(l<r)
		for(j=1;j<=7;j++)sum[i].n[j]=sum[i<<1].n[j]+sum[i<<1|1].n[j];
}
void update(int i,int l,int r,int a,int b,int v)
{
	if(l==a&&r==b)
	{
		if(v<0) --cnt[i][-v];
		else ++cnt[i][v];
		Pushup(i,l,r);
		return ;
	}
	int mid=(l+r)>>1;
	if(b<=mid) update(i<<1,l,mid,a,b,v);
	else if(b>mid&&a<=mid)
	{
		update(i<<1,l,mid,a,mid,v);
		update(i<<1|1,mid+1,r,mid+1,b,v);
	}
	else update(i<<1|1,mid+1,r,a,b,v);
	Pushup(i,l,r);
}

int Bin(int l,int r,__int64 v)
{
	int mid;
	while(l<=r)
	{
		mid=(l+r)>>1;
		if(X[mid]==v) return mid;
		else if(X[mid]>v) r=mid-1;
		else l=mid+1;
	}
	return -1;
}
int main()
{
	char op[5];
	int cas,cass,n,k,m,i,j;
	__int64 x1,x2,y1,y2,ans[8];
	scanf("%d",&cass);
	for(cas=1;cas<=cass;cas++)
	{
		m=0;
		scanf("%d",&n);
		while(n--)
		{
			scanf("%s%I64d%I64d%I64d%I64d",op,&x1,&y1,&x2,&y2);
			if(op[0]=='R')k=1;
			if(op[0]=='G')k=2;
			if(op[0]=='B')k=3;
			Set(m,x1,y1,x2,y2,k);
			m+=2;
		}
		sort(X,X+m);
		sort(line,line+m);
		for(i=k=1;i<m;i++)
			if(X[i-1]<X[i])
				X[k++]=X[i];
		int l,r;
		memset(ans,0,sizeof(ans));
		memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
		for(i=0;i<m-1;i++)
		{
			l=Bin(0,k-1,line[i].x1);
			r=Bin(0,k-1,line[i].x2)-1;
			if(l<=r)update(1,0,k-1,l,r,line[i].v);
			for(j=1;j<=7;j++)
				ans[j]+=sum[1].n[j]*(line[i+1].h-line[i].h);
		}
		printf("Case %d:\n",cas);
		for(i=1;i<=7;i++)
			printf("%I64d\n",ans[t[i]]);
	}
	return 0;
}

/*
10
2
G 0 0 2 2
B 1 1 3 3
*/


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值