HDU 4419 Colourful Rectangle --离散化+线段树扫描线
题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积。
解法: 很容易想到线段树扫描线求矩形面积并,但是如何维护每种颜色的长度着实让我伤透了脑筋。后来看了一位朋友的题解,才幡然醒悟。
开始想到了用二进制表示颜色,R用001表示,G用010表示,B用100表示。那么就可以用十进制1~7表示7种不同颜色了。
维护 cov[rt][1~3] 表示此区间内3种原色各有多少个, Len[rt][i]表示每种颜色的长度。
重点是pushup的写法,详情见代码, 离散化什么还比较简单。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define lll __int64 using namespace std; #define N 10107 lll Len[7*N][8]; int cov[7*N][4]; struct Line { int y1,y2,x; int col; }line[2*N]; int yy[2*N]; int cmp(Line ka,Line kb) { return ka.x < kb.x; } void pushup(int l,int r,int rt) { int state = 0; for(int i=1;i<=3;i++) if(cov[rt][i]) state |= (1<<(i-1)); //表示此区间内有的颜色 for(int i=0;i<8;i++) Len[rt][i] = 0; //加了一层,要重新算各个颜色的长度 if(l+1 == r) //叶子节点 { Len[rt][state] = yy[r]-yy[l]; //只有此颜色state,长度为yy[r]-yy[l] return; } for(int i=0;i<8;i++) //否则使用下面的更新 Len[rt][i|state] += Len[2*rt][i] + Len[2*rt+1][i]; } void build(int l,int r,int rt) { for(int i=1;i<=3;i++) cov[rt][i] = 0; for(int i=1;i<8;i++) Len[rt][i] = 0; Len[rt][0] = yy[r]-yy[l]; if(l == r-1) return; int mid = (l+r)/2; build(l,mid,2*rt); build(mid,r,2*rt+1); } void update(int l,int r,int aa,int bb,int cover,int rt) { if(aa <= l && bb >= r) { if(cover > 0) cov[rt][cover]++; else cov[rt][-cover]--; pushup(l,r,rt); return; } if(l+1 == r) return; int mid = (l+r)/2; if(aa <= mid) update(l,mid,aa,bb,cover,2*rt); if(bb > mid) update(mid,r,aa,bb,cover,2*rt+1); pushup(l,r,rt); } int main() { int n,m,t,cs = 1,i,j; int x1,y1,x2,y2,c; char ss[4]; scanf("%d",&t); while(t--) { m = 1; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%s%d%d%d%d",ss,&x1,&y1,&x2,&y2); if(ss[0] == 'R') c = 1; else if(ss[0] == 'G') c = 2; else c = 3; line[m].x = x1,line[m].y1 = y1,line[m].y2 = y2,line[m].col = c,yy[m++] = y1; line[m].x = x2,line[m].y1 = y1,line[m].y2 = y2,line[m].col = -c,yy[m++] = y2; } m--; sort(yy+1,yy+m+1); int cnt = 2; for(i=2;i<=m;i++) { if(yy[i] != yy[i-1]) yy[cnt++] = yy[i]; } cnt--; build(1,cnt,1); sort(line+1,line+m+1,cmp); lll ans[8]; memset(ans,0,sizeof(ans)); printf("Case %d:\n",cs++); for(i=1;i<m;i++) { int L = lower_bound(yy+1,yy+cnt+1,line[i].y1)-yy; int R = upper_bound(yy+1,yy+cnt+1,line[i].y2)-yy-1; update(1,cnt,L,R,line[i].col,1); for(j=1;j<8;j++) ans[j] += Len[1][j]*(line[i+1].x-line[i].x); } 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; }
作者:whatbeg
出处1:http://whatbeg.com/
出处2:http://www.cnblogs.com/whatbeg/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
更多精彩文章抢先看?详见我的独立博客: whatbeg.com