转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526 by---cxlove
题目:给出3种颜色,重叠会生成新的颜色,然后有一些矩形,求出每种颜色的面积
http://acm.hdu.edu.cn/showproblem.php?pid=4419
很明显的矩形面积并,线段树+离散化+扫描线,当时也没有多想,就丢给阳哥了
其实不太好处理,有7种颜色,可是 状态压缩一下
1,2,4表示三原色。
学习到了一种写法,比较简单
首先记录某个区间内覆盖的次数,然后更新
保证上层正确,用下层各种颜色更新上层,利用不变降复杂度
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<queue>
#define inf 1<<28
#define M 6000005
#define N 11005
#define maxn 300005
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define MOD 1000000007
#define lson step<<1
#define rson step<<1|1
using namespace std;
struct segment{
int x1,x2,y,val;
segment(){}
segment(int _x1,int _x2,int _y,int _v):x1(_x1),x2(_x2),y(_y),val(_v){}
bool operator<(const segment s)const{
return y<s.y;
}
}seg[N*2];
struct Node{
int left,right,len[8],cnt[5];
}L[N*2*4];
int x[N*2]={-1},cnt;
LL ans[8];
void Bulid(int step,int l,int r){
L[step].left=l;
L[step].right=r;
mem(L[step].len,0);
mem(L[step].cnt,0);
if(l==r) return;
int m=(l+r)>>1;
Bulid(lson,l,m);
Bulid(rson,m+1,r);
}
void Push_Up(int step){
//当前区间的状态,然后求长度
int state=(L[step].cnt[1]>0?1:0)|(L[step].cnt[2]>0?2:0)|(L[step].cnt[4]>0?4:0);
if(state){
mem(L[step].len,0);
//统计长度
L[step].len[state]=x[L[step].right+1]-x[L[step].left];
for(int i=1;i<8;i++){
//如果原来有别的颜色
if(state!=(state|i)){
int tmp=L[lson].len[i]+L[rson].len[i];
//混合色增加
L[step].len[state|i]+=tmp;
//原来的颜色减少
L[step].len[state]-=tmp;
}
}
}
else if(L[step].left!=L[step].right)
for(int i=1;i<8;i++) L[step].len[i]=L[lson].len[i]+L[rson].len[i];
//这步不能少,当前为叶子,置0
else mem(L[step].len,0);
}
void Update(int step,int l,int r,int val){
if(L[step].left==l&&r==L[step].right)
val>0?++L[step].cnt[val]:--L[step].cnt[-val];
else{
int m=(L[step].left+L[step].right)>>1;
if(r<=m) Update(lson,l,r,val);
else if(l>m) Update(rson,l,r,val);
else{
Update(lson,l,m,val);
Update(rson,m+1,r,val);
}
}
Push_Up(step);
}
int Bin(int m){
int low=1,high=cnt,mid;
while(low<=high){
mid=(low+high)>>1;
if(x[mid]==m) return mid;
if(x[mid]<m) low=mid+1;
else high=mid-1;
}
}
int main(){
int t,cas=0,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=0;i<n;i++){
char str[6];
int x1,x2,y1,y2;
scanf("%s%d%d%d%d",str,&x1,&y1,&x2,&y2);
seg[2*i]=segment(x1,x2,y1,str[0]=='R'?1:(str[0]=='G'?2:4));
seg[2*i+1]=segment(x1,x2,y2,str[0]=='R'?-1:(str[0]=='G'?-2:-4));
x[2*i+2]=x1;x[2*i+1]=x2;
}
sort(seg,seg+2*n);
sort(x+1,x+1+2*n);
cnt=0;
for(int i=1;i<=2*n;i++)
if(x[i]!=x[cnt])
x[++cnt]=x[i];
Bulid(1,1,cnt);
mem(ans,0);
//不明白为什么i<2*n-1就不行,最后一条线段还需要计算?
for(int i=0;i<2*n;i++){
//离散化,段化为点
int l=Bin(seg[i].x1),r=Bin(seg[i].x2)-1;
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)*(LL)L[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]);
}
return 0;
}