题目链接:http://acm.hdu.edu.cn/viewcode.php?rid=32159923
题目大意:有n个矩形块,这些矩形块有R, G, B三种不同的颜色,最终区域的颜色由该区域上颜色的种类决定,要求输出 R, G, B, RG, RB, GB, RGB七种颜色的面积是多少。
思路:在前面区域覆盖面积的例题里,我们用一维数组维护被覆盖的区间长度,因为这里有颜色之分,所以可以再开一维表示颜色。此外,区域的颜色是由不同颜色的种类决定的,所以颜色的判断就可以很好地利用到或运算。
- (扫描线中为什么不用push_down)扫描线的例题中利用了线段树这种数据结构,但是我们每次查询的都是整体,没有去询问某个子区间,且最终结果与覆盖顺序无关,所以不用push_down。
AC1:
//cover[root][i]表示区间被第i种颜色覆盖的次数
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define mid ((l + r)>>1)
#define chl root<<1
#define chr root<<1|1
using namespace std;
typedef unsigned long long ull;
typedef long long LL;
const int manx=2e4+10;
int sum[manx<<3][8],cover[manx<<3][3],X[manx<<1],n;
struct node
{
int y,lx,rx,color;
int val;
friend bool operator<(node a,node b)
{
return a.y<b.y;
}
}line[manx<<1];
void init()
{
memset(sum,0,sizeof(sum));
memset(cover,0,sizeof(cover));
}
void eval(int root,int l,int r)
{
int white=X[r+1]-X[l],Color=0;
for(int i=0; i<=2; i++)
if(cover[root][i])
Color|=(1<<i);
for(int i=1; i<=7; i++)
sum[root][i]=0;
for(int i=1; i<=7; i++)
{
sum[root][i|Color]+=sum[chl][i]+sum[chr][i];
white-=sum[chl][i]+sum[chr][i];
}
if(Color)
sum[root][Color]+=white;
}
void change(int root,int l,int r,int ll,int rr,int color,int val)
{
if(l==ll&&r==rr)
{
cover[root][color]+=val;
eval(root,l,r);
return;
}
if(rr<=mid)
change(chl,l,mid,ll,rr,color,val);
else if(ll>mid)
change(chr,mid+1,r,ll,rr,color,val);
else
{
change(chl,l,mid,ll,mid,color,val);
change(chr,mid+1,r,mid+1,rr,color,val);
}
eval(root,l,r);
}
int main()
{
int t,x1,y1,x2,y2,Cas=0;;
char str[2];
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
init();
for(int i=1; i<=n; i++)
{
int color;
scanf("%s%d%d%d%d",str,&x1,&y1,&x2,&y2);
if(str[0]=='R')
color=2;
else if(str[0]=='G')
color=1;
else
color=0;
line[2*i]=node{y1,x1,x2,color,1};
X[2*i]=x1;
line[2*i-1]=node{y2,x1,x2,color,-1};
X[2*i-1]=x2;
}
sort(line+1,line+2*n+1);
sort(X+1,X+2*n+1);
int cnt=unique(X+1,X+2*n+1)-X-1;
LL ans[8]= {0};
for(int i=1; i<2*n; i++)
{
int l=lower_bound(X+1,X+cnt+1,line[i].lx)-X;
int r=lower_bound(X+1,X+cnt+1,line[i].rx)-X-1;
int dy=line[i+1].y-line[i].y;
change(1,1,cnt,l,r,line[i].color,line[i].val);
for(int i=1; i<=7; i++)
ans[i]+=(LL)sum[1][i]*(LL)dy;
}
printf("Case %d:\n",++Cas);
printf("%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n",ans[4],ans[2],ans[1],ans[6],ans[5],ans[3],ans[7]);
}
return 0;
}
AC2:
记录一下当时找bug时的心情。。真的MLE到哭泣。
本来觉得找到了扫描线的快乐,后面把sum的第二维降到了7(sum[][7]),然后又试了下vector存数据,结果都超内存了,重要的是后面发现又是一个沙雕错误:把lower_bound里面的cnt写成了2*n
后面找博客还发现自己之前的思路有些复杂:cover可以只用记录三种颜色出现的次数,回溯更新覆盖区间长度时 再判断最终的颜色,这样cover的操作会简单很很很多
//cover[root][i]表示区间被i种颜色覆盖次数
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
using namespace std;
//#define int long long
#define LL long long
#define ull unsigned long long
#define pii pair<int,int>
#define mid ((l + r)>>1)
#define chl (root<<1)
#define chr (root<<1|1)
#define lowbit(x) ( x&(-x) )
const int manx = 2e4 + 10;
const int INF = 2e9;
const int mod = 1e4+7;
int color[manx<<2][3];
LL X[manx],sum[manx<<2][8];
//struct node
//{
// int color[3];
// LL sum[8];
//}tree[manx<<2];
struct EDGE
{
LL y,lx,rx;
int val,color;
friend bool operator<(const EDGE &a,const EDGE &b){
return a.y<b.y;
}
}edge[manx];
void init()
{
memset(color,0,sizeof color);
memset(sum,0,sizeof sum);
}
void eval(int root,int l,int r)
{
int C=0,white=X[r+1]-X[l];
for(int i=0;i<=2;i++)
if(color[root][i])C|=(1<<i);
memset(sum[root],0,sizeof sum[root]);
if(l==r){
sum[root][C]=white;
return;
}
for(int i=0;i<=7;i++){
sum[root][C|i]+=sum[chl][i]+sum[chr][i];
white-=sum[chl][i]+sum[chr][i];
}
sum[root][C]+=white;
}
void change(int root,int l,int r,int ll,int rr,int val,int C)
{
if(l==ll&&r==rr){
color[root][C]+=val;
eval(root,l,r);
return;
}
if(rr<=mid)
change(chl,l,mid,ll,rr,val,C);
else if(ll>mid)
change(chr,mid+1,r,ll,rr,val,C);
else{
change(chl,l,mid,ll,mid,val,C);
change(chr,mid+1,r,mid+1,rr,val,C);
}
eval(root,l,r);
}
int main()
{
int t,n,Cas=0,cou;
char col[2];
LL x1,x2,y1,y2;
scanf("%d",&t);
while(t--){
init();
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s%lld%lld%lld%lld",col,&x1,&y1,&x2,&y2);
int C;
if(col[0]=='R')C=0;
else if(col[0]=='G')C=1;
else C=2;
edge[i*2-1]=EDGE{y1,x1,x2,1,C};
edge[i*2]=EDGE{y2,x1,x2,-1,C};
X[i*2-1]=x1;
X[i*2]=x2;
}
sort(edge+1,edge+2*n+1);
sort(X+1,X+2*n+1);
cou=unique(X+1,X+2*n+1)-X-1;
LL ans[8]={0};
for(int i=1;i<2*n;i++){
int l=lower_bound(X+1,X+cou+1,edge[i].lx)-X;
int r=lower_bound(X+1,X+cou+1,edge[i].rx)-X-1;
LL dy=edge[i+1].y-edge[i].y;
change(1,1,cou,l,r,edge[i].val,edge[i].color);
if(!dy)continue;
for(int i=1;i<=7;i++)
ans[i]+=sum[1][i]*dy;
}
printf("Case %d:\n",++Cas);
printf("%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n",ans[1],ans[2],ans[4],ans[3],ans[5],ans[6],ans[7]);
}
return 0;
}