题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4419
题意:给出平面上一些矩形,这些矩形的颜色有三种R、G、B。相交的区域分别标记为 RG, RB, GB, RGB。输出颜色为R, G, B, RG, RB, GB, RGB的面积各为多少?
思路:比赛的时候想着跟标准的矩形面积并相比,要输出各种颜色的面。当时想,只能在线段树的节点上改变以记录每种颜色,看别人的容斥原理才明白,原来可以这样干:设上面7种颜色的面积分别为1,2,3,4,5,6,7:
a=1+2+3+4+5+6+7(把所有的矩形求一次面积交)
b=1+2+4+5+6+7(把R和G的矩形求一次)
c=2+3+4=5+6+7(把G和B的矩形求一次)
d=1+3+4+5+6+7(把R和B的矩形求一次)
e=1+4+5+7(把R的矩形求一次)
f=2+4+6+7(把G的矩形求一次)
g=3+5+6+7(把B的矩形求一次)
由以上七个式子可以得到:
1=a-c;
2=a-d;
3=a-b;
6=a-2-3-e;
5=a-1-3-f;
4=a-1-2-g;
7=a-1-2-3-4-5-6;
问题迎刃而解。。。
struct NODE
{
char color[5];
__int64 x1,y1,x2,y2;
};
struct Node
{
__int64 L,R;
__int64 Len; //当前,本区间上有多长的部分是落在那些矩形中的
__int64 cover; //本区间当前被多少个矩形完全包含
};
struct node
{
__int64 x,y1,y2;
bool bLeft;
node(){}
node(__int64 _x,__int64 _y1,__int64 _y2,bool _bLeft)
{
x=_x;
y1=_y1;
y2=_y2;
bLeft=_bLeft;
}
};
const int MAX=10005;
NODE p[MAX];
node L[MAX*2];
Node a[MAX*10];
__int64 y[MAX*2];
int n;
bool cmp(node a,node b)
{
return a.x<b.x;
}
inline int DB(__int64 x)
{
if(x==0) return 0;
return x>0?1:-1;
}
int find(__int64 y[],int n,__int64 val)
{
int low=0,high=n-1,mid;
while(low<=high)
{
mid=(low+high)>>1;
if(DB(val-y[mid])==0) return mid;
if(DB(val-y[mid])==1) low=mid+1;
else high=mid-1;
}
if(DB(val-y[0])==0) return 0;
return n-1;
}
void insert(int t,int L,int R)
{
if(a[t].L==L&&a[t].R==R)
{
a[t].Len=y[R+1]-y[L];
a[t].cover++;
return;
}
int mid=(a[t].L+a[t].R)>>1;
if(R<=mid) insert(t*2,L,R);
else if(L>mid) insert(t*2+1,L,R);
else
{
insert(t*2,L,mid);
insert(t*2+1,mid+1,R);
}
if(a[t].cover==0) a[t].Len=a[t*2].Len+a[t*2+1].Len;
}
void del(int t,int L,int R)
{
if(a[t].L==L&&a[t].R==R)
{
a[t].cover--;
if(a[t].cover==0)
{
if(a[t].L==a[t].R) a[t].Len=0;
else a[t].Len=a[t*2].Len+a[t*2+1].Len;
}
return;
}
int mid=(a[t].L+a[t].R)>>1;
if(R<=mid) del(t*2,L,R);
else if(L>mid) del(t*2+1,L,R);
else
{
del(t*2,L,mid);
del(t*2+1,mid+1,R);
}
if(a[t].cover==0) a[t].Len=a[t*2].Len+a[t*2+1].Len;
}
void build(int t,int L,int R)
{
a[t].L=L;
a[t].R=R;
a[t].cover=0;
a[t].Len=0;
if(L==R) return;
int mid=(L+R)>>1;
build(t*2,L,mid);
build(t*2+1,mid+1,R);
}
__int64 cal_cross_area(NODE p[],int n)
{
if(!n) return 0;
int i,k;
__int64 x1,y1,x2,y2;
for(i=0;i<n;i++)
{
x1=p[i].x1;
y1=p[i].y1;
x2=p[i].x2;
y2=p[i].y2;
y[i*2]=y1;
y[i*2+1]=y2;
L[i*2]=node(x1,y1,y2,true);
L[i*2+1]=node(x2,y1,y2,false);
}
sort(y,y+2*n);
sort(L,L+2*n,cmp);
k=unique(y,y+2*n)-y;
build(1,0,k-2);
__int64 ans=0;
for(i=0;i<2*n-1;i++)
{
int left=find(y,k,L[i].y1) ;
int right=find(y,k,L[i].y2) ;
if(L[i].bLeft) insert(1,left,right-1);
else del(1,left,right-1);
ans+=((__int64)a[1].Len)*(L[i+1].x-L[i].x);
}
return ans;
}
int C,num=0;
int main()
{
for(scanf("%d",&C);C--;)
{
scanf("%d",&n);
int i;
__int64 x1,y1,x2,y2;
for(i=0;i<n;i++)
{
scanf("%s%I64d%I64d%I64d%I64d",p[i].color,&x1,&y1,&x2,&y2);
p[i].x1=x1;
p[i].y1=y1;
p[i].x2=x2;
p[i].y2=y2;
}
__int64 a,b,c,d,e,f,g;
a=cal_cross_area(p,n);
NODE Q[MAX];
int N;
N=0;
for(i=0;i<n;i++) if(p[i].color[0]=='R'||p[i].color[0]=='G')
Q[N++]=p[i];
b=cal_cross_area(Q,N);
N=0;
for(i=0;i<n;i++) if(p[i].color[0]=='B'||p[i].color[0]=='G')
Q[N++]=p[i];
c=cal_cross_area(Q,N);
N=0;
for(i=0;i<n;i++) if(p[i].color[0]=='R'||p[i].color[0]=='B')
Q[N++]=p[i];
d=cal_cross_area(Q,N);
N=0;
for(i=0;i<n;i++) if(p[i].color[0]=='R')
Q[N++]=p[i];
e=cal_cross_area(Q,N);
N=0;
for(i=0;i<n;i++) if(p[i].color[0]=='G')
Q[N++]=p[i];
f=cal_cross_area(Q,N);
N=0;
for(i=0;i<n;i++) if(p[i].color[0]=='B')
Q[N++]=p[i];
g=cal_cross_area(Q,N);
__int64 _1,_2,_3,_4,_5,_6,_7;
_1=a-c;
_2=a-d;
_3=a-b;
_6=a-_2-_3-e;
_5=a-_1-_3-f;
_4=a-_1-_2-g;
_7=a-_1-_2-_3-_4-_5-_6;
printf("Case %d:\n",++num);
printf("%I64d\n%I64d\n%I64d\n%I64d\n%I64d\n%I64d\n%I64d\n",_1,_2,_3,_4,_5,_6,_7);
}
return 0;
}