HDU 4419 Colourful Rectangle(线段树)

题目链接: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;
 }

  

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值