题目大意:给出一些有颜色的矩形,会重叠,问最后每种颜色的面积为多少。。
当时网络赛不会做,最近学习了一下大神的做法,总算明白了。
我们可以将 三基色 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]); } }