hdu 4419 2012杭州网络赛

题目大意:给出一些有颜色的矩形,会重叠,问最后每种颜色的面积为多少。。

当时网络赛不会做,最近学习了一下大神的做法,总算明白了。

我们可以将 三基色 RGB 以及其 衍生出来的其他颜色 化成 二进制表示 xxx,三位分别表示BGB ,那么 001 就是 R,010就是G,

100就是B,011就是 RG。。。以此类推,就构成了7个状态,开辟线段树,记录每个区间每种颜色的 长度用扫描线从左往右扫描

即可。

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

#define MAXN 10005
#define lson u<<1
#define rson u<<1|1
#define CLR(a,b) memset(a,0,sizeof(a))
#define LL long long

int x[MAXN<<1];
LL ans[8];

struct segment{
	int x1,x2,y,val;
	segment(){}
	segment(int a,int b,int c,int d):x1(a),x2(b),y(c),val(d){}
	bool operator < (const segment& cmp)const{
		return y<cmp.y;
	}
}seg[MAXN<<1];

struct Node{
	int lef,rig,len[8],cnt[5];//len记录每种颜色的长度,cnt记录RGB三基色是否存在
}T[MAXN<<3];

void Build(int u,int l,int r){
	T[u].lef=l;
	T[u].rig=r;
	CLR(T[u].len,0);
	CLR(T[u].cnt,0);
	if(l==r)return;
	int mid=(l+r)>>1;
	Build(lson,l,mid);
	Build(rson,mid+1,r);
}

void PushUp(int u){
	CLR(T[u].len,0);//叶子节点,长度为清0
	int state=(T[u].cnt[1]>0?1:0)|(T[u].cnt[2]>0?2:0)|(T[u].cnt[4]>0?4:0);//三基色混在一起生成的状态,或操作
	if(state){
		T[u].len[state]+=x[T[u].rig]-x[T[u].lef-1];//记录混合色的长度
		for(int i=1;i<8;i++){
			if(state!=(state|i)){//判断原来是否还有其他颜色
				int tmp=T[lson].len[i]+T[rson].len[i];
				T[u].len[state|i]+=tmp;//新混合色长度增加
				T[u].len[state]-=tmp;//原来的颜色减少
			}
		}
	}
	//如果本区间没有三基色,那么本区间的颜色长度将直接从左右儿子获得
	else if(T[u].lef!=T[u].rig)for(int i=1;i<8;i++)T[u].len[i]=T[lson].len[i]+T[rson].len[i];
}

void Update(int u,int l,int r,int val){
	if(l<=T[u].lef&&T[u].rig<=r){
		val>0?++T[u].cnt[val]:--T[u].cnt[-val];
	}
	else {
		if(l<=T[lson].rig)Update(lson,l,r,val);
		if(r>=T[rson].lef)Update(rson,l,r,val);
	}
	PushUp(u);
}

int main(){

	int t,n;
	char color;
	int x1,y1,x2,y2;

	scanf("%d",&t);
	for(int cas=1;cas<=t;cas++){
		scanf("%d",&n);
		int num=0;
		for(int i=0;i<n;i++){
			scanf(" %c%d%d%d%d",&color,&x1,&y1,&x2,&y2);
			x[num]=x1;
			seg[num++]=segment(x1,x2,y1,color=='R'?1:(color=='G'?2:4));
			x[num]=x2;
			seg[num++]=segment(x1,x2,y2,color=='R'?-1:(color=='G'?-2:-4));
		}
		sort(x,x+num);
		sort(seg,seg+num);
		int xnum=unique(x,x+num)-x;//去重
		Build(1,1,xnum);
		CLR(ans,0);
		for(int i=0;i<num;i++){
			int l=lower_bound(x,x+xnum,seg[i].x1)-x+1;//离散化。。
			int r=lower_bound(x,x+xnum,seg[i].x2)-x;
			Update(1,l,r,seg[i].val);
			if(seg[i].y!=seg[i+1].y)for(int j=1;j<8;j++)ans[j]+=(LL)(seg[i+1].y-seg[i].y)*T[1].len[j];
		}
		printf("Case %d:\n",cas);
		printf("%I64d\n%I64d\n%I64d\n%I64d\n%I64d\n%I64d\n%I64d\n",ans[1],ans[2],ans[4],ans[3],ans[5],ans[6],ans[7]);
	}

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值